home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / asmutil / asm_n_z.zip / TED2.ASM < prev    next >
Assembly Source File  |  1989-09-12  |  79KB  |  2,365 lines

  1. NAME    TED
  2. PAGE    58,132
  3. TITLE    TED -- the Tiny EDitor
  4. ;=======================================================================
  5. ; TED.ASM -- The Tiny EDitor.
  6. ; PC Magazine * Tom Kihlken * 11/15/88
  7. ;
  8. ; See the article "The tiniest editor you'll ever need" by Tom Kihlken, 
  9. ; in the November 15, 1988 issue of PC Magazine for more detail than is 
  10. ; presented here.  Portions of this text are excerpted from that article.  
  11. ; The source listing, itself, was copied directly from that article and 
  12. ; altered as appropriate to add comments or change or improve the program.
  13. ; The use of self-modifying code for "NO_DESNOW" is discussed in the article.
  14. ; SEGment register usage have been cleaned up to reduce the size of the code.
  15. ;
  16. ; TED follows normal text conventions: pressing the <Enter> key actually 
  17. ; adds two characters, Carriage-return (ASCII 13) and Line-feed (ASCII 10), 
  18. ; also known as a "hard carriage return".  The <Tab> key inserts the ASCII 9 
  19. ; tab character, and advances the screen cursor to the next column that is 
  20. ; an even multiple of eight.  The <Backspace> key deletes the character to 
  21. ; its immediate left ("destructive" backspace) and combines two lines if it 
  22. ; is pressed while in the first column.  The Backspace code (Ctrl-H) may be 
  23. ; entered in the file as a control code.  TED2 allows the ASCII codes for 
  24. ; Carriage-Return (Ctrl-M) and Line-feed (Ctrl-J) to independently be entered 
  25. ; into the file as control codes.  Because of this, TED2 rigidly enforces 
  26. ; a convention that once the <Ctrl-M><Ctrl-J> pair is formed it becomes an 
  27. ; End-of-line marker, and may not be separated again.   
  28. ;
  29. ; Like DOS, TED lets you enter any character (except <Nul>, value 00) by 
  30. ; holding down the Alt key, typing the decimal value of its ASCII code on 
  31. ; the numeric keypad, then releasing Alt.  This gives you access both to 
  32. ; nonprinting codes below ASCII 32 and to the upper-order (ASCII 128 to 255) 
  33. ; characters in the extended IBM set.  TED2 allows the <Nul> code to be 
  34. ; entered by pressing the <Shft-F1> key.
  35. ;
  36. ; NOTE: Unassigned keyboard codes are treated as no-operations.
  37. ;
  38. ; The TED Keypad commands are:
  39. ; Key            Description
  40. ; Up Arrow        Moves cursor up one row
  41. ; Down Arrow        Moves cursor down one row
  42. ; Left Arrow        Moves cursor left one column
  43. ; Right Arrow        Moves cursor right one column
  44. ; PgUp            Moves text window up one page
  45. ; PgDn            Moves text window down one page
  46. ;>Home            Moves cursor to start of row (if at home, next up)
  47. ;>End            Moves cursor to end of row (if at end, next end down)
  48. ; Ins            Toggles insert/overstrike mode
  49. ; Del            Deletes character (right) at cursor (saved in UnDo)
  50. ; Backspace        Deletes character (left) at cursor (not saved in UnDo)
  51. ; Ctrl-PgUp        Moves to top of file
  52. ;>Ctrl-Home        Moves to top of file (alias)
  53. ; Ctrl-PgDn        Moves to bottom of file
  54. ;>Ctrl-End        Moves to bottom of file (alias)
  55. ; Ctrl-Right Arrow    Moves text window right eight columns
  56. ; Ctrl-Left Arrow    Moves text window left eight columns
  57. ;
  58. ; Alt-S    Search        Search for (case insensitive) character string
  59. ; Alt-A Search Again    Search again for string
  60. ; Alt-D    Del EOL        Deletes from cursor to the end of line
  61. ;
  62. ; The TED Editing Functions are:
  63. ; Key    Function    Operation
  64. ; F1    Help         Help screen
  65. ; ShftF1 <Nul>        Enters the <Nul> code (value 00) in the file
  66. ; F2    Exit        Save changes and exit (creates a .BAK file)
  67. ; ShftF2 Quit        Exit without saving changes
  68. ; F3    Print        Prints the marked text
  69. ; F4    Mark        Toggles mark state on/off
  70. ; F5    Cut        Moves marked text to paste buffer
  71. ; ShftF5 Paste        Inserts contents of paste buffer (64K char's max)
  72. ; F6    Search        Search for (case insensitive) character string
  73. ; ShftF6 Search Again    Search again for string
  74. ; F7    UnDo        Replaces recently DELeted characters (256 char's max)
  75. ; F8    Del EOL        Deletes from cursor to the end of line
  76. ; ShftF8 Del L        Deletes the current line (MultiEdit)
  77. ; F9    Del L        Deletes the current line
  78. ; F10    Udel L        Inserts the last deleted line (256 char's max)
  79. ;
  80. ; In addition to the 64K Text buffer (where the edit file is maintained), 
  81. ; there are three other important buffers, as indicated above.  
  82. ;   1.) The paste buffer is a 64K character buffer used for MARK/CUT/PASTE of 
  83. ;    sections of the file.
  84. ;   2.) The line buffer is a 256 character buffer used to save the last 
  85. ;     deleted line of text (used with F8, F9 and F10).
  86. ;   3.) The UnDo buffer is a 256 character buffer used to save the just 
  87. ;    deleted characters at the current cursor location.  It works with 
  88. ;     the "DEL" key, but only the last character with the "Backspace" key.  
  89. ;     It also saves overwritten characters in the Overstrike mode.  
  90. ;     Deletions are restored with "F7" UnDo.
  91. ;
  92. ; NOTE: There is a severe subroutine nesting violation in the TED key scan 
  93. ; routine.  BAD_KEY from within the keyboard scanning loop is a junp to 
  94. ; read next key.  The BAD_KEY subroutine calls through the DISPATCH_TABLE 
  95. ; do not have a corresponding return to equalize the stack.  This was 
  96. ; partially compensated for by making the stack humongous.  TED 1.0 as 
  97. ; published in PC Magazine could eventually overflow the stack and crash the 
  98. ; system.  TED2 has corrected this problem by making a stub subroutine for 
  99. ; the DISPATCH_TABLE BAD_KEY subroutine CALLs.
  100. ;
  101. ; TED was modified by James E. Galbraith, Dec 18, 1988.
  102. ; The changes are of several types.  Compatability with other editors.  
  103. ; Correction of errors and questionable code.  Reordering of program modules 
  104. ; to make it easier to follow the listing.  Addition of meaningful comments.
  105. ; These modifications include:
  106. ;    Change F2 "UnDo" to "Exit" (for BSE compatibility).
  107. ;    Change F7 "Exit" to "UnDo".
  108. ;    Make CTRL-HOME alias to CTRL-PGUP, to home the cursor (for BSE).
  109. ;    Make CTRL-END alias to CTRL-PGDN, cursor to end of file (for BSE).
  110. ;    JMP instructions outside modules instead of CALL/RETurn are commentd.
  111. ;    Assignment of DS was sometimes ambiguous.  
  112. ;
  113. ; Modified by James E. Galbraith, June 1989.
  114. ; The changes are in two groups.  Those taken from TEDPLUS (apparently also 
  115. ; written by Tom Kihlken), which was acquired from a bulletin board service, 
  116. ; and my own changes.
  117. ;    Add SEARCH and SEARCH AGAIN as F6 and Shft-F6, from TEDPLUS.
  118. ;    Delete CPM style Ctrl-Z End-of-file code, from TEDPLUS.
  119. ;    "Enter any key code" from TEDPLUS was included, but not like TEDPLUS
  120. ;    End-of-line was changed to CR-LF as in TEDPLUS.  CR or LF codes may be 
  121. ;      entered separately.
  122. ; My own changes are:
  123. ;    Close the source file if it has been opened.  This was not done by TED.
  124. ;    Add a HELP screen as <F1>, move QUIT to <Shft-F2>.
  125. ;    Fix the SEARCH inverse video to turn off when any key is pressed.
  126. ;    Add DOS version check, needs version 2.0 or higher to run.
  127. ;    Add a program checksum test for verification of file integrity.
  128. ;    Add <Alt-S> as alias for <F6> SEARCH (usage in BSE editor).
  129. ;    Add <Alt-A> as alias for <Shft-F6> SEARCH AGAIN (usage in BSE editor).
  130. ;    Add <Alt-D> as alias for <Shft-F8>, Delete to end of line.
  131. ;    Add <Shft-F8> as alias for <F9>, Delete Line (for future expansion).
  132. ;    If the file has not been altered, don't prompt for save or quit.
  133. ;    On QUIT, accept a CR as confirmation of intention to abandon file.
  134. ;    Add <Shft-F1> as key to enter the <Nul> character, 00.
  135. ;    If a CR and LF code are made to be ajacent, they become an EOL marker, 
  136. ;      and may not then be separated.  This can occur in several ways that 
  137. ;      all include entering the codes <Crtl-M> and <Ctrl-J>. 
  138. ;    A key entry will interrupt a screen update that is in progress.
  139. ;      
  140.  
  141. ; Assemble the TED2.ASM source file to TED2.COM by using the MASM.EXE assembler, 
  142. ; the linker LINK.EXE, and the file conversion utility EXE2BIN.EXE, as follows:
  143. ; The checksum byte can be obtained with TEST.BAT (included with TED2.ASM).
  144. ;
  145. ;    MASM TED2;
  146. ;    LINK TED2;
  147. ;    EXE2BIN TED2 TED2.COM
  148. ;-----------------------------------------------------------------------
  149. CSEG        SEGMENT
  150.         ASSUME    CS:CSEG, DS:CSEG, ES:CSEG
  151.         ORG    0100H
  152. START:
  153.         JMP    BEGIN
  154.  
  155. ;-----------------------------------------------------------------------
  156. ; Local data area in CSEG.
  157. ;-----------------------------------------------------------------------
  158. ; ASCII character values used in the program.
  159. TAB        EQU    9
  160. CR        EQU    13
  161. LF        EQU    10
  162. CRLF        EQU    0A0DH
  163.  
  164. ; Character strings and data
  165. COPYRIGHT    DB    "TED 1.0 (C) 1988 Ziff Communications Co.,"
  166.         DB    "PC Magazine, 11/15/88, by Tom Kihlken"
  167.         DB    CR,LF,"TED 2.1, 9/12/89, by James E. Galbraith"
  168.         DB    CR,LF,"$"
  169.  
  170.         ;(JEG)
  171. HELP_SCREEN    DB    9,9,'TED - the Tiny EDitor (any key to edit)',CR
  172.                 DB      LF,LF,9,'F1 - Help',9,9,9,'Shft-F1 - <NUL> char'
  173.         DB    CR,LF,9,'F2 - Exit and save',9,9,'Shft-F2 - Quit'
  174.         DB    CR,LF,9,'F3 - Print marked',9,9,'Shft-F3 - Form-feed'
  175.         DB    CR,LF,9,'F4 - Mark toggle'
  176.         DB    CR,LF,9,'F5 - Cut marked',9,9,9,'Shft-F5 - Paste'
  177.         DB    CR,LF,9,'F6 - String search',9,9,'Shft-F6 - '
  178.         DB    'Search again'
  179.         DB    CR,LF,9,'F7 - Undo <Del> or Ovr'
  180.         DB    CR,LF,9,'F8 - Delete to EOL' ;** ,9,9,'Shft-F8 - '
  181.     ;**    DB    'Delete Line'
  182.         DB    CR,LF,9,'F9 - Delete Line'
  183.         DB    CR,LF,9,'F10 - Un-Delete line',LF
  184.         DB    CR,LF,9,'Ctrl-L/R arrow - Move window'
  185.         DB    CR,LF,9,'Ctrl-Home - to top'
  186.         DB    CR,LF,9,'Ctrl-End - to EOF',LF
  187.         DB    CR,LF,9,'Esc - From Exit'
  188.         DB    CR,LF,'$',7,1AH
  189.  
  190.         ;from JEG and TEDPLUS
  191. PROMPT_STRING    DB    "1Help",0        ;F1
  192.         DB    "2Exit",0        ;F2
  193.         DB    "3Print",0        ;F3
  194.         DB    "4Mark",0        ;F4
  195.         DB    "5Cut",0        ;F5
  196.         DB    "6Search",0        ;F6
  197.         DB    "7UnDo",0        ;F7
  198.         DB    "8Del EOL",0        ;F8
  199.         DB    "9Del L",0        ;F9
  200.         DB    "10Udel L",0,0        ;F10
  201. PROMPT_LENGTH    =    $ - OFFSET PROMPT_STRING
  202.  
  203. FILE_TOO_BIG    DB    "File too big$"
  204. READ_ERR_MESS    DB    "Read error$"
  205. MEMORY_ERROR    DB    "Not enough memory$"
  206.  
  207.         ;(JEG)
  208. CHEK_SUM_MESS    DB    "TED altered$"
  209. DOS_2_MESS    DB    "Needs DOS 2.0$"
  210.  
  211. VERIFY_MESS    DB    "Lose Changes (Y)?",0
  212. SAVE_MESS    DB    "Save as: ",0
  213. DOT_$$$        DB    ".$$$",0
  214. DOT_BAK        DB    ".BAK",0
  215.  
  216.         ;from TEDPLUS, string search
  217. SRCH_PROMPT    DB    "SEARCH> ",0
  218. ;SRCH_MAX    DB    66        ;(moved to file end to reduce file size)
  219. ;SRCH_SIZ    DB    0
  220. ;SRCH_STR    DB    66 DUP (0)
  221. SRCH_FLG    DB    0        ;0=normal, 1=search successful (inverse)
  222. SRCH_END    DW    0
  223. SRCH_BASE    DW    0
  224. SRCH_CLR    DB    0F0H        ;244
  225.  
  226. DIRTY_BITS    DB    03H        ;1=update screen, 2=cursor 4=cur. line
  227. DIRTY_FILE    DB    0        ;0=file not altered, FF=file altered
  228.  
  229. NORMAL        DB    07H        ;video attribute bits
  230. INVERSE        DB    70H        ;video (inverse)
  231.  
  232. LEFT_MARGIN    DB    0        ;column number of screen left margin
  233. MARGIN_COUNT    DB    0
  234. INSERT_MODE    DB    01H        ;1=INSert, 0=Overstrike, 2or3=Read Only
  235. INSERT_CODE    DB    'OIRR'        ;indexed code for display screen
  236. MARK_MODE    DB    0        ;toggle, FF=MARK is on.
  237. ROWS        DB    23        ;Rows available on display screen
  238. SAVE_COLUMN    DB    0
  239. SAVE_ROW    DB    0
  240. LINE_FLAG    DB    0
  241.  
  242. EVEN                    ;"word align" (for 16-bit bus accesses)
  243. NAME_POINTER    DW    81H        ;offset of command tail in PSP
  244. NAME_END    DW    81H        ;end of tail
  245.  
  246. VIDEO_STATUS_REG LABEL    DWORD        ;(alias for use by LES instruction)
  247. STATUS_REG    DW    0        ;video status register offset
  248. VIDEO_SEG    DW    0B000H        ;video segment, Mono=0B000, other 0B800
  249.  
  250. LINE_LENGTH    DW    0        ;number of bytes in current line
  251. UNDO_LENGTH    DW    0        ;number of DELeted bytes in UnDo buffer
  252. CURS_POSN    DW    0        ;Cursor, Hi is row, Low is column
  253.  
  254. MARK_START    DW    0FFFFH        ;MARK text for CUT/PASTE or Print
  255. MARK_END    DW    0
  256. MARK_HOME    DW    0
  257.  
  258. TOP_OF_SCREEN    DW    0        ;address in text file of Top-of-screen
  259. CURSOR        DW    0        ;address in text file of cursor
  260. LAST_CHAR    DW    0        ;address of last character in file.
  261. COLUMNSB    LABEL    BYTE        ;alias BYTE definition
  262. COLUMNS        DW    0
  263.  
  264. PASTE_SEG    DW    0        ;segment address of PASTE buffer
  265. PASTE_SIZE    DW    0        ;size of block in PASTE buffer
  266.  
  267. PAGE_PROC    DW    0        ;pointer used by PGUP and PGDN
  268.  
  269. EXIT_CODE    DW    4C00H        ;DOS INT 21H, Func 4CH, exit with code
  270.  
  271. OLDINT24    DD    0        ;pointer to DOS critical error handler
  272.  
  273. DISPATCH_BASE    EQU    59      ;initial offset for a PASCAL type CASE list
  274. DISPATCH_TABLE    DW    HELP      ;59;F1, Help screen (common usage)
  275.         DW    EXIT      ;60;F2, Save changes and exit (from BSE)
  276.         DW    PRINT      ;61;F3, Print the marked text
  277.         DW    MARK      ;62;F4, Toggle mark state on/off
  278.         DW    CUT      ;63;F5, Move marked text to buffer
  279.         DW    FIND_STR  ;64;F6, Search for text string
  280.         DW    UNDO      ;65;F7, Replace recently deleted chars
  281.         DW    DEL_EOL      ;66;F8, Delete from cursor to EOL
  282.         DW    DEL_L      ;67;F9, Delete the current line
  283.         DW    UDEL_L      ;68;F10, Insert the last deleted line
  284.         DW    BAD_KEY      ;69;(NumLock)
  285.         DW    BAD_KEY      ;70;(ScrollLock)
  286.         DW    HOME_KEY  ;71;Home/7
  287.         DW    UP      ;72;Up/8
  288.         DW    PGUP      ;73;PgUp/9
  289.         DW    BAD_KEY      ;74;(-)
  290.         DW    LEFT      ;75;Left/4
  291.         DW    BAD_KEY      ;76;(5)
  292.         DW    RIGHT      ;77;Right/6
  293.         DW    BAD_KEY      ;78;(+)
  294.         DW    END_KEY      ;79;End/1
  295.         DW    DOWN      ;80;Down/2
  296.         DW    PGDN      ;81;PgDn/3
  297.         DW    INSERT      ;82;Ins/3
  298.         DW    DEL_CHAR  ;83;Del/.
  299.  
  300.         DW    NUL_CHAR  ;84;Shft-F1 -- Add NUL character to file
  301.         DW    ABORT      ;85;Shft-F2 -- Quit and abandon changes
  302.         DW    PRINT_FF  ;86;Shft-F3 -- Print a form-feed character
  303.         DW    BAD_KEY      ;87;Shft-F4
  304.         DW    PASTE      ;88;Shft-F5 -- Insert contents of Paste buffer
  305.         DW    FIND_STR  ;89;Shft-F6 -- Search again for string
  306.         DW    BAD_KEY      ;90;Shft-F7
  307.         DW    DEL_L      ;91;Shft-F8 -- Delete line (Multi-Edit)
  308. DISPATCH_END    EQU    92
  309.         ;--------------------------------
  310.         ; gap in keyboard scan code assignments
  311.         ;--------------------------------
  312. DISP_CURS_BASE    EQU    115
  313.         DW    SH_LEFT   ;115;Ctrl-Left arrow
  314.         DW    SH_RIGHT  ;116;Ctrl-Right arrow
  315.         DW    BOTTOM    ;117;Ctrl-End
  316.         DW    CTRL_PGDN ;118;Ctrl-PgDn
  317.         DW    TOP      ;119;Ctrl-Home
  318. DISP_CURS_END    EQU    120
  319.  
  320. ;**        DW    CTRL_PGUP ;132;Ctrl-PgUp
  321.  
  322. ;---------------------------------
  323. ; The following constant is a machine instruction that removes the CGA desnow 
  324. ; delay.  It is inserted into the code for EGA, VGA, and mono displays.
  325. ; See the article in PC-Magazine for further discussion.
  326.  
  327. NO_DESNOW = (OFFSET WRITE_IT - OFFSET HWAIT - 2) * 256 + 0EBH ;opcode JMP SHORT
  328.  
  329. ;=======================================================================
  330. ; We start by initialize the display, then allocate memory for the file
  331. ; and paste segments.  Parse the command line for the filename, if one was 
  332. ; input, read in the file.  Finally set the INT 23 and 24 vectors.
  333. ;-----------------------------------------------------------------------
  334. BEGIN:
  335.         MOV    AH,30H        ;get DOS version (JEG new)
  336.         INT    21H
  337.         CMP    AL,2
  338.         JAE    DOS_2_UP
  339.         MOV    EXIT_CODE,0    ;is DOS version 1, exit with function 0.
  340.         MOV    DX,OFFSET DOS_2_MESS ;message "Needs DOS 2.0"
  341. ;**short    JMP    EXIT_TO_DOS
  342.         JMP    SHORT EXIT_22_DOS ;(saves a byte)
  343.         ;-----------------------
  344. DOS_2_UP:
  345.         ;JEG new -- program code checksum test
  346.         MOV    SI,100H        ;start of program file.
  347.         MOV    SP,SI        ;set stack pointer to top of PSP.
  348.         MOV    CX,OFFSET CHEK_SUM_BYT - 0100H ;size of program file.
  349.         MOV    AL,CHEK_SUM_BYT    ;load checksum correction factor byte.
  350. CHKSUM_LOOP:    ADD    AL,[SI]        ;add all program code bytes together.
  351.         INC    SI
  352.         LOOP    CHKSUM_LOOP
  353.         CMP    AL,0        ;is program checksum zero?
  354.         JZ    CHEKSUM_IS_OK    ;yes, continue with program
  355.         NEG    AL        ;make error into correction factor.
  356.         MOV    BYTE PTR EXIT_CODE,AL ;save errorlevel code for exit.
  357.         MOV    DX,OFFSET CHEK_SUM_MESS ;message "TED altered".
  358. ;**short    JMP    EXIT_TO_DOS    ;error message and exit to DOS
  359. ;EXIT_22_DOS:    JMP    SHORT EXIT_2_DOS ;error message and exit to DOS
  360. EXIT_22_DOS:    JMP    EXIT_2_DOS    ;error message and exit to DOS
  361.         ;-----------------------
  362. CHEKSUM_IS_OK:
  363.         XOR    AX,AX
  364.         MOV    DS,AX        ;zero DS
  365.         ASSUME    DS:NOTHING
  366.         MOV    BL,10H
  367.         MOV    AH,12H        ;get EGA info
  368.         INT    10H
  369.         CMP    BL,10H        ;did BL change?
  370.         JE    NOT_EGA        ;if not, no EGA in system
  371.         TEST    BYTE PTR DS:[0487H],8 ;is EGA active?
  372.         JNZ    NOT_EGA
  373.         MOV    WORD PTR CS:HWAIT,NO_DESNOW ;get rid of desnow
  374.         MOV    AX,DS:[0484H]    ;get number of rows
  375.         DEC    AL        ;last row is for prompt line
  376.         MOV    CS:[ROWS],AL    ;save the number of rows
  377. NOT_EGA:
  378.         MOV    AX,DS:[044AH]    ;get number of columns
  379.         MOV    CS:COLUMNS,AX    ;and store it
  380.         MOV    AX,DS:[0463H]    ;address of display card
  381.         ADD    AX,6        ;add six to get status port
  382.         PUSH    CS
  383.         POP    DS
  384.         ASSUME    DS:CSEG
  385.         MOV    STATUS_REG,AX
  386.         CMP    AX,3BAH        ;is this a MONO display?
  387.         JNE    COLOR        ;if not, must be a CGA
  388.         MOV    WORD PTR HWAIT,NO_DESNOW ;get rid of desnow
  389.         JMP    SHORT MOVE_STACK
  390.  
  391. COLOR:
  392.         MOV    VIDEO_SEG,0B800H ;segment for color card
  393.         XOR    BH,BH        ;use page zero
  394.         MOV    AH,8        ;get current attribute
  395.         INT    10H
  396.         AND    AH,77H        ;turn off blink and high intensity
  397.         MOV    NORMAL,AH    ;save the normal attribute
  398.         XOR    AH,01110111B    ;flip the color bits
  399.         MOV    INVERSE,AH
  400.         OR    AH,80H
  401.         MOV    SRCH_CLR,AH    ;search is inverse/blink
  402. MOVE_STACK:
  403.         MOV    BX,OFFSET END_BUFFER
  404. ;**rounding    ADD    BX,15        ;add offset value for SEG rounding up
  405.         MOV    CL,4        ;convert program size to 
  406.         SHR    BX,CL        ; paragraphs
  407.         MOV    AH,4AH        ;deallocate unused memory
  408.         INT    21H        ;DOS call
  409.         MOV    BX,1000H    ;request 64K for file segment
  410.         MOV    AH,48H
  411.         INT    21H        ;DOS call
  412.         MOV    ES,AX
  413.         ASSUME    ES:FILE_SEG
  414.         MOV    AH,48H        ;request 64K for paste buffer
  415.         INT    21H        ;DOS call
  416.         JNC    GOT_ENOUGH    ;if enough memory, continue
  417. NOT_ENOUGH:
  418.         MOV    DX,OFFSET MEMORY_ERROR
  419.  
  420. EXIT_2_DOS:    JMP    EXIT_TO_DOS    ;jump island to allow SHORT jumps.
  421.         ;-----------------------
  422. GOT_ENOUGH:
  423.         MOV    PASTE_SEG,AX    ;use this for the paste buffer
  424. GET_FILENAME:
  425.         MOV    SI,80H        ;point to command tail in PSP
  426.         MOV    CL,[SI]        ;get number of characters in tail
  427.         XOR    CH,CH        ;make it a word
  428.         INC    SI        ;point to first character
  429.         PUSH    SI
  430.         ADD    SI,CX        ;point to last character
  431.         MOV    BYTE PTR [SI],0    ;make it an ASCIIZ string (clear the CR)
  432.         MOV    NAME_END,SI    ;save pointer to last character
  433.         POP    SI        ;get back pointer to filename
  434.         JCXZ    NO_FILENAME    ;if no params, just exit
  435.         CLD
  436. DEL_SPACES:
  437.         LODSB            ;get character into AL
  438.         CMP    AL," "        ;is it a space?
  439.         JNE    FOUND_LETTER
  440.         LOOP    DEL_SPACES
  441. FOUND_LETTER:
  442.         DEC    SI        ;backup pointer to first letter
  443.         MOV    NAME_POINTER,SI    ;save pointer to filename
  444.  
  445.         MOV    DX,NAME_POINTER
  446.         MOV    AX,4300H    ;get file attribute byte (in CL)
  447.         INT    21H        ;DOS call
  448.         JC    ATTRIB_ERROR
  449.         AND    CL,1        ;keep bit-0, read-only status
  450.         ADD    CL,CL        ;shift RO bit up 
  451.         OR    INSERT_MODE,CL    ;save as index modifier value
  452. ATTRIB_ERROR:
  453.         MOV    DX,SI
  454.         MOV    AX,3D00H    ;setup to open file
  455.         INT    21H        ;DOS call
  456.         ; If no carry, Then the opened file handle is in AX
  457.         ; If no carry, Then the opened file handle is in AX
  458.         JC    NO_FILENAME    ;if we can't open, must be new file
  459. FILE_OPENED:
  460.         PUSH    ES
  461.         POP    DS        ;DS has file segment also
  462.         ASSUME    DS:FILE_SEG
  463.         MOV    BX,AX        ;get the handle into BX
  464.         XOR    DX,DX        ;point to file buffer, DS:DX
  465.         MOV    CX,0FFFEH    ;read almost 64K bytes
  466.         MOV    AH,3FH        ;read from file or device
  467.         ; BX = file handle
  468.         INT    21H        ;DOS call
  469.         ; If no carry, Then AX contains number of bytes read
  470.         MOV    DI,AX        ;number of bytes read in
  471.         JNC    FILE_READ_OK    ;if no error, take jump
  472.         MOV    DX,OFFSET READ_ERR_MESS
  473.         ;-----------------------
  474.         ; the file has been opened, it should now be closed. (JEG)
  475.         ;-----------------------
  476. CLOSE_ERR_EXIT:
  477.         MOV    AH,3EH        ;close the opened file
  478.         ; BX = file handle
  479.         INT    21H
  480.         JMP    SHORT EXIT_2_DOS
  481.         ;-----------------------
  482. FILE_READ_OK:
  483.         MOV    LAST_CHAR,DI    ;save the file size
  484.         CMP    CX,AX        ;did the buffer fill?
  485.         MOV    DX,OFFSET FILE_TOO_BIG
  486.         JE    CLOSE_ERR_EXIT    ;if yes, it is too big
  487.         MOV    AH,3EH        ;close the file
  488.         ; BX = file handle
  489.         INT    21H
  490. ;**dirty    MOV    BYTE PTR CS:DIRTY_FILE,0 ;file opened but not altered.
  491. NO_FILENAME:
  492.         PUSH    ES
  493.         PUSH    ES        ;save the file segment
  494.         PUSH    CS
  495.         POP    DS
  496.         ASSUME    DS:CSEG
  497.         ;-----------------------
  498.         ;INT 24 is the critical error handler
  499.         ;-----------------------
  500.         MOV    AX,3524H    ;get INT 24 vector
  501.         INT    21H        ;DOS call
  502.         MOV    WORD PTR OLDINT24,BX   ;store the offset
  503.         MOV    WORD PTR OLDINT24+2,ES ;and the segment
  504.         MOV    DX,OFFSET NEWINT24 ;point to new vector
  505.         MOV    AX,2524H    ;now change INT 24 vector
  506.         INT    21H        ;DOS call
  507.         ;-----------------------
  508.         ;INT 23 is the CTRL-Break or CTRL-C handler
  509.         ;-----------------------
  510.         MOV    DX,OFFSET NEWINT23
  511.         MOV    AX,2523H    ;set the INT 23 vector
  512.         INT    21H        ;DOS call
  513.  
  514.         POP    ES        ;get back file segment
  515.         POP    DS
  516.         ASSUME    DS:FILE_SEG
  517.         CALL    REDO_PROMPT    ;draw the prompt line
  518.  
  519. ;-----------------------------------------------------------------------
  520. ; Here's the main loop.  It updates the screen, then reads a keystroke.
  521. ;-----------------------------------------------------------------------
  522. READ_A_KEY:
  523.         CMP    MARK_MODE,0    ;is the mark state on?
  524.         JZ    MARK_OFF    ;if not, skip this
  525.         OR    DIRTY_BITS,4    ;refresh the current row
  526.         MOV    DX,CURS_POSN
  527.         CMP    SAVE_ROW,DH    ;are we on the save row?
  528.         JE    SAME_ROW    ;if yes, then redo the row only
  529.         OR    DIRTY_BITS,1    ;refresh the whole screen
  530. SAME_ROW:
  531.         MOV    AX,CURSOR    ;get cursor location
  532.         MOV    BX,MARK_HOME    ;get the anchor mark position
  533.         CMP    AX,BX        ;moving backward in file?
  534.         JAE    SAME1
  535.         MOV    MARK_START,AX    ;switch start and end positions
  536.         MOV    MARK_END,BX
  537.         JMP    SHORT MARK_OFF
  538. SAME1:
  539.         MOV    MARK_END,AX    ;store start and end marks
  540.         MOV    MARK_START,BX
  541. MARK_OFF:
  542.         CALL    DISPLAY_SCREEN    ;redraw the screen
  543.  
  544.                 XOR     AH,AH           ;read the next key (wait if none ready)
  545.         INT    16H        ;BIOS call
  546.         ; AL = ASCII code or 0 (for function keys)
  547.         ; AH = scan code
  548.                 TEST    SRCH_FLG,0FFH
  549.         JZ    CHECK_KEY    ;jump if inverse not on
  550.         MOV    SRCH_FLG,0    ;turn off highlight
  551.         OR    DIRTY_BITS,1    ;redraw screen (next time)
  552. CHECK_KEY:
  553.         OR    AL,AL        ;is this an extended code?
  554.         JZ    IS_EXTENDED_CODE ;(jump if not an ASCII character)
  555.          CALL    INSERT_KEY    ;put this ASCII character in the file
  556. ;**short    JMP    READ_A_KEY    ;get another key
  557.         JMP    SHORT RD_NEXT_KEY ;get another key
  558. ;---------------------------------------
  559.  
  560. IS_EXTENDED_CODE:
  561.         ;-----------------------
  562.         ; The following code is for "orphan" key codes and alias keys
  563.         ;-----------------------
  564.         CMP    AH,132        ;is it Ctrl-PgUp? (an orphan code)
  565.         JNE    NOT_CT_PGUP
  566.         CALL    CTRL_PGUP
  567. ;**short    JMP    READ_A_KEY
  568.         JMP    SHORT RD_NEXT_KEY ;get another key
  569.         ;-----------------------
  570. NOT_CT_PGUP:
  571.         CMP    AH,32        ;is it Alt-D (MultiEdit Del-EOL)?
  572.         JNE    NOT_ALT_D
  573.         MOV    AH,66        ;substitute scan code for F8
  574. NOT_ALT_D:
  575.         CMP    AH,31        ;is it Alt-S (BSE string search)?
  576.         JNE    NOT_ALT_S
  577.         MOV    AH,64        ;substitute scan code for F6
  578. NOT_ALT_S:
  579.         CMP    AH,30        ;is it Alt-A (BSE search again)?
  580.         JNE    NOT_ALT_A
  581.         MOV    AH,89        ;substitute scan code for Shft-F6
  582. NOT_ALT_A:
  583.         ;-----------------------
  584.         ; The following code sets up a PASCAL style CASE statement.
  585.         ;-----------------------
  586.         CMP    AH,DISPATCH_END    ;split the dispatch table
  587.         JB    DO_DISPATCH
  588.         ;-----------------------
  589.         ; offset cursor group of keys to join the regular dispatch table.
  590.         ;-----------------------
  591.         CMP    AH,DISP_CURS_BASE
  592.         JB    RD_NEXT_KEY
  593.         CMP    AH,DISP_CURS_END
  594.         JAE    RD_NEXT_KEY
  595.         SUB    AH,LOW (DISP_CURS_BASE - DISPATCH_END) ;close table gap
  596. DO_DISPATCH:
  597.         ;-----------------------
  598.         ; This is a PASCAL style CASE statement.
  599.         ;-----------------------
  600.         MOV    BX,AX        ;put AH offset value in BX, AL=0
  601.         XCHG    BL,BH        ;make into a proper word
  602.         SUB    BX,DISPATCH_BASE ;zero offset for dispatch table jump
  603.         JC    RD_NEXT_KEY    ;too low, not in table
  604.         ADD    BX,BX        ;make into word
  605.         CALL    CS:DISPATCH_TABLE[BX] ;call the key procedure
  606. RD_NEXT_KEY:    JMP    READ_A_KEY    ;then read another key
  607.  
  608.  
  609. ;=======================================================================
  610. ; KEYBOARD and CURSOR services
  611. ;=======================================================================
  612. ; These two routines shift the display right or left to allow editing 
  613. ; files which contain lines longer than 80 columns.  Starting with TED2, 
  614. ; they are proper subroutines.  
  615. ;-----------------------------------------------------------------------
  616. SH_LEFT        PROC    NEAR
  617.         CMP    LEFT_MARGIN,0    ;at start of line already?
  618.         JE    NO_SHIFT    ;if yes,then don't shift
  619.         SUB    LEFT_MARGIN,8    ;move the window over
  620.         JMP    SHORT SH_RETURN
  621. SH_LEFT        ENDP
  622. ;-----------------------------------------------------------------------
  623. SH_RIGHT    PROC    NEAR
  624.         CMP    LEFT_MARGIN,255 - 8 ;past max allowable margin?
  625.         JAE    NO_SHIFT    ;then can't move any more
  626.         ADD    LEFT_MARGIN,8    ;this moves the margin over
  627. SH_RETURN:
  628.         CALL    CURSOR_COL    ;compute column for cursor
  629.         MOV    SAVE_COLUMN,DL    ;save the current column
  630.         OR    DIRTY_BITS,1    ;redraw the screen
  631. NO_SHIFT:
  632. ;**dispatch    JMP    READ_A_KEY
  633. ;**bad_key    RET
  634. SH_RIGHT    ENDP
  635.  
  636. ;-----------------------------------------------------------------------
  637. ; DISPATCH_TABLE calls to BAD_KEY now go here so that the stack can be 
  638. ; kept equallized.  
  639. ;-----------------------------------------------------------------------
  640. BAD_KEY        PROC    NEAR
  641.         RET
  642. BAD_KEY        ENDP
  643.  
  644. ;=======================================================================
  645. ; This routine moves the cursor to the top of the file.
  646. ;-----------------------------------------------------------------------
  647. TOP        PROC    NEAR
  648.         XOR    AX,AX        ;get a zero into AX
  649.         MOV    CURSOR,AX    ;cursor to start of file
  650.         MOV    TOP_OF_SCREEN,AX
  651.         MOV    LEFT_MARGIN,AL    ;move to far left margin
  652.         MOV    CURS_POSN,AX    ;home the cursor
  653.         MOV    SAVE_COLUMN,AL    ;save the cursor column
  654.         MOV    DIRTY_BITS,3    ;redraw the screen and cursor
  655.         RET
  656. TOP        ENDP
  657.  
  658. ;=======================================================================
  659. ; This routine moves the cursor to the bottom of the file.
  660. ;-----------------------------------------------------------------------
  661. BOTTOM        PROC    NEAR
  662.         MOV    DH,ROWS        ;get screen size
  663.         MOV    SI,LAST_CHAR    ;point to last character
  664.         ;-----------------------
  665.         ; from TEDPLUS
  666.         DEC    SI
  667.         ;-----------------------
  668.         MOV    LEFT_MARGIN,0    ;set window to start of line
  669.         CALL    LOCATE        ;adjust the cursor screen position
  670.         CALL    HOME        ;move cursor to start of line
  671.         MOV    DIRTY_BITS,1    ;this will redraw the screen
  672.         RET
  673. BOTTOM        ENDP
  674.  
  675. ;=======================================================================
  676. ; This routine moves the cursor to the start of the current line.
  677. ; If <HOME> key and already at start of line, move to start of previous line.
  678. ;-----------------------------------------------------------------------
  679. HOME_KEY    PROC    NEAR
  680.         CALL    LEFT        ;back up one space, in case at home
  681. HOME_KEY    ENDP
  682.  
  683. HOME        PROC    NEAR
  684.         CALL    FIND_START    ;find start of line
  685.         MOV    CURSOR,SI    ;save the new cursor
  686.         MOV    SAVE_COLUMN,0    ;save the cursor column
  687.  
  688.         MOV    BYTE PTR CURS_POSN,0 ;store the column number
  689.         RET
  690. HOME        ENDP
  691.  
  692. ;=======================================================================
  693. ; These routines move the cursor right and left
  694. ;-----------------------------------------------------------------------
  695. RIGHT        PROC    NEAR
  696.         MOV    SI,CURSOR
  697.         CMP    SI,LAST_CHAR    ;at end of file?
  698.         JE    LR_NO_CHANGE    ;if yes, then can't move
  699.         ;-----------------------
  700.         ; from TEDPLUS
  701.         INC    SI
  702.         CMP    SI,LAST_CHAR    ;at end of file?
  703.         DEC    SI
  704.         JAE    INC_RIGHT    ;if yes, then increment
  705.         CMP    WORD PTR [SI],CRLF ;is it CRLF?
  706.         JE    MOVE_DOWN    ;if yes, then move down to next line
  707. INC_RIGHT:
  708.         ;-----------------------
  709.         INC    CURSOR        ;advance the cursor
  710.         JMP    SHORT LR_RETURN
  711. MOVE_DOWN:
  712.         CALL    HOME        ;move to start of line
  713.         JMP    SHORT DOWN    ;and move down one row
  714.         ;(CALL/RETurn)
  715. RIGHT        ENDP
  716. ;-----------------------------------------------------------------------
  717. LEFT        PROC    NEAR
  718.         CMP    CURSOR,0    ;at start of file?
  719.         JZ    LR_NO_CHANGE    ;then can't move left
  720.         MOV    DX,CURS_POSN
  721.         OR    DL,DL        ;at first column?
  722.         JZ    MOVE_UP        ;if yes, then move up one
  723.         DEC    CURSOR        ;shift the cursor offset
  724. LR_RETURN:
  725.         CALL    CURSOR_COL    ;compute column for cursor
  726.         MOV    SAVE_COLUMN,DL    ;save the cursor column
  727. LR_NO_CHANGE:
  728.         MOV    UNDO_LENGTH,0
  729.         RET
  730.         ;-----------------------
  731. MOVE_UP:
  732.         CALL    UP        ;move up to next row
  733.         JMP    SHORT ENDD    ;and move to end of line
  734.         ;(CALL/RETurn)
  735. LEFT        ENDP
  736.  
  737. ;-----------------------------------------------------------------------
  738. ; This routine moves the cursor to the end of the current line.
  739. ; If END key and already at end of line, move to end of next line.
  740. ;-----------------------------------------------------------------------
  741. END_KEY        PROC    NEAR
  742.         CALL    RIGHT        ;move one space right, if at EOL
  743. END_KEY        ENDP
  744.  
  745. ENDD        PROC    NEAR
  746.         MOV    SI,CURSOR
  747.         CALL    FIND_EOL    ;find end of this line
  748.         MOV    CURSOR,SI    ;store the new cursor
  749.         CALL    CURSOR_COL    ;compute the correct column
  750.         MOV    SAVE_COLUMN,DL    ;save the cursor column
  751.         RET
  752. ENDD        ENDP
  753.  
  754. ;-----------------------------------------------------------------------
  755. ; This routine moves the cursor down one row.  When the last row is reached, 
  756. ; the screen is shifted up one row.
  757. ;-----------------------------------------------------------------------
  758. DOWN        PROC    NEAR
  759.         MOV    UNDO_LENGTH,0
  760.         MOV    DX,CURS_POSN
  761.         CMP    DH,ROWS        ;at bottom row already?
  762.         MOV    SI,CURSOR    ;get position in file
  763.         JE    SCREEN_UP    ;if at bottom, then scroll up
  764.         CALL    FIND_NEXT    ;find the start of next line
  765.         JC    DOWN_RET    ;if no more lines, then return
  766.         MOV    CURSOR,SI
  767.         INC    DH        ;advance cursor to next row
  768.         CALL    SHIFT_RIGHT    ;move cursor to current column
  769. DOWN_RET:
  770.         RET
  771.         ;-----------------------
  772. SCREEN_UP:
  773.         CMP    SI,LAST_CHAR    ;get cursor offset
  774.         JE    DOWN_RET
  775.         CALL    FIND_START    ;find the start of this line
  776.         MOV    CURSOR,SI    ;this is the new cursor
  777.         CALL    FIND_NEXT    ;find the offset of next line
  778.         JC    SHIFT_RET    ;if no more lines, then return
  779.         MOV    CURSOR,SI    ;this is the new cursor
  780.         MOV    SI,TOP_OF_SCREEN ;get the start of the top row
  781.         CALL    FIND_NEXT    ;and find the next line
  782.         MOV    TOP_OF_SCREEN,SI ;store the new top of screen
  783.         JMP    SHORT SHIFT_RET
  784.         ;(CALL/RETurn)
  785. DOWN        ENDP
  786.  
  787. ;-----------------------------------------------------------------------
  788. ; This routine moves the cursor up one row.  If the cursor is at the first row, 
  789. ; the screen is scrolled down.
  790. ;-----------------------------------------------------------------------
  791. UP        PROC    NEAR
  792.         MOV    UNDO_LENGTH,0
  793.         MOV    DX,CURS_POSN
  794.         MOV    SI,CURSOR
  795.         OR    DH,DH        ;at top row already?
  796.         JZ    SCREEN_DN    ;if yes, then scroll down
  797.         DEC    DH        ;move the cursor up one row
  798.         CALL    FIND_CR        ;find the beginning of this row
  799.         MOV    CURSOR,SI
  800.         CALL    FIND_START    ;find start of this row
  801.         MOV    CURSOR,SI
  802.         CALL    SHIFT_RIGHT    ;skip over to current column
  803. AT_TOP:
  804.         RET
  805.         ;-----------------------
  806. SCREEN_DN:
  807.         MOV    SI,TOP_OF_SCREEN
  808.         OR    SI,SI        ;at start of file?
  809.         JZ    AT_TOP        ;if at top, then do nothing
  810.         CALL    FIND_PREVIOUS    ;find the preceding line
  811.         MOV    TOP_OF_SCREEN,SI ;save new top of screen
  812.         MOV    SI,CURSOR
  813.         CALL    FIND_PREVIOUS    ;find the preceding line
  814.         MOV    CURSOR,SI    ;this is the new cursor
  815. SHIFT_RET:
  816.         OR    DIRTY_BITS,1    ;need to redraw the screen
  817.         MOV    SI,CURSOR
  818.         MOV    DX,CURS_POSN
  819.         JMP    SHIFT_RIGHT    ;move cursor to current column
  820.         ;(CALL/RETurn)
  821. UP        ENDP
  822.  
  823. ;=======================================================================
  824. ; These four routines move the screen one page at a time by calling the 
  825. ; UP and DOWN procedures.
  826. ;-----------------------------------------------------------------------
  827. CTRL_PGDN    PROC    NEAR    ;do PgDn then PgUp
  828.         CALL    PGDN
  829.         JMP    SHORT PGUP
  830.         ;(CALL/RETurn)
  831. CTRL_PGDN    ENDP
  832. ;-----------------------------------------------------------------------
  833. PGUP        PROC    NEAR
  834.         MOV    CS:PAGE_PROC,OFFSET UP
  835.         JMP    SHORT PAGE_UP_DN
  836. PGUP        ENDP
  837. ;-----------------------------------------------------------------------
  838. CTRL_PGUP    PROC    NEAR    ;do PgUp then PgDn
  839.         CALL    PGUP
  840. ;**        JMP    SHORT PGDN
  841.         ;(CALL/RETurn)
  842. CTRL_PGUP    ENDP
  843. ;-----------------------------------------------------------------------
  844. PGDN        PROC    NEAR
  845.         MOV    CS:PAGE_PROC,OFFSET DOWN
  846. PAGE_UP_DN:
  847.         MOV    CL,CS:ROWS    ;get vertical length of screen
  848.         SUB    CL,5        ;don't page a full screen
  849.         XOR    CH,CH        ;make it a word
  850. PAGE_LOOP:
  851.         PUSH    CX
  852.         CALL    PAGE_PROC    ;move the cursor down
  853.         POP    CX
  854.         LOOP    PAGE_LOOP    ;loop for one page length
  855.         RET
  856. PGDN        ENDP
  857.  
  858. ;=======================================================================
  859. ; This routine toggles the Insert/Overstrike mode.
  860. ;-----------------------------------------------------------------------
  861. INSERT        PROC    NEAR
  862.     ;    ASSUME    DS:NOTHING
  863. ;**RO mode    NOT    CS:INSERT_MODE    ;toggle the switch
  864.         XOR    CS:INSERT_MODE,1 ;toggle the "I/O" switch
  865.         CALL    REDO_PROMPT ;redraw the insert/overstrike status
  866.         RET
  867. INSERT        ENDP
  868.  
  869. ;=======================================================================
  870. ; FILE MANIPULATION services
  871. ;=======================================================================
  872. ; This routine forces the insertion of the NUL character, 00H, in the file.
  873. ;-----------------------------------------------------------------------
  874. NUL_CHAR    PROC    NEAR
  875.         XOR    AX,AX
  876. NUL_CHAR    ENDP
  877.  
  878. ;-----------------------------------------------------------------------
  879. ; This routine adds a character into the file.  In insert mode, remaining 
  880. ; characters are pushed forward.  If the scan code for <Enter> is detected, 
  881. ; a <CR><LF> pair is added as the EOL marker.  If the scan code for 
  882. ; <Backspace> is detected, the character to the left of the cursor is 
  883. ; deleted (unless the cursor is already at the start of the file).  
  884. ;-----------------------------------------------------------------------
  885. INSERT_KEY    PROC    NEAR
  886.         ASSUME    DS:FILE_SEG
  887.         MOV    SI,CS:CURSOR
  888.  
  889.         CMP    CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  890.         JA    FILE_FULL    ;jump if read-only file
  891.  
  892.         CMP    AH,28        ;was this the <Enter> key scan code?
  893.         JE    NEW_LINE    ;if yes, make new line: <CR><LF>.
  894.  
  895.         CMP    AH,14        ;was it the <Backspace> key scan code?
  896.         JE    BACK_SPACE    ;if yes, delete character left.
  897.  
  898.         CMP    CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  899.         JE    INSERT_CHAR    ;jump if Insert
  900.         ;-----------------------
  901.         ; test for overstrike character at end of line or file.
  902.         ; if EOL or EOF, then insert rather than overstrike.
  903.         ;-----------------------
  904.         CMP    SI,CS:LAST_CHAR    ;at end of file?
  905.         JAE    INSERT_CHAR
  906.         INC    SI
  907.         CMP    SI,CS:LAST_CHAR    ;at end of file?
  908.         DEC    SI
  909.         JAE    INSERT_CHAR
  910.         CMP    WORD PTR [SI],CRLF ;at end of line?
  911.         JE    INSERT_CHAR
  912.  
  913. OVERSTRIKE_NOT_AT_CRLF:
  914.         MOV    DI,SI
  915.         PUSH    AX        ;save new character
  916.         XCHG    DS:[SI],AL    ;switch new character for old one
  917.         CALL    SAVE_CHAR    ;store the old character
  918.         POP    AX        ;get back new character
  919.         JMP    SHORT ADVANCE
  920. ;---------------------------------------
  921. INSERT_CHAR:
  922.         PUSH    SI
  923.         PUSH    AX        ;save the new character
  924.         MOV    AX,1
  925.         CALL    OPEN_SPACE    ;make room for it at SI
  926.         POP    AX        ;get back the new character
  927.         POP    DI
  928.         JC    FILE_FULL
  929.         STOSB            ;insert character in file buffer, ES:DI
  930. ADVANCE:
  931.         OR    CS:DIRTY_BITS,4    ;current line is dirty
  932.  
  933.         ;-----------------------
  934.         ; see if we made a CR-LF pair by adding a Ctrl-M with a Ctrl-J
  935.         ;-----------------------
  936.         CALL    C_IF_NEW_CRLF    ;see if in middle of new CR-LF
  937.         JC    FILE_FULL    ;jump if new line was done
  938.         ;------------------------
  939.         CMP    AL,CR        ;was key <Ctrl-M> - CR?
  940.         JNE    INS_NOT_CR
  941.         MOV    CS:DIRTY_BITS,1    ;redraw the screen (just in case EOL)
  942. INS_NOT_CR:
  943.         ;-----------------------
  944.         PUSH    UNDO_LENGTH
  945.         CALL    RIGHT        ;move cursor to next letter
  946.         POP    UNDO_LENGTH
  947. FILE_FULL:
  948.         RET
  949.  
  950. CR_AT_EOF:
  951.         INC    CS:CURSOR
  952.         RET
  953.  
  954. ;---------------------------------------
  955. ; process the <Enter> key, make new line
  956. ;---------------------------------------
  957. NEW_LINE:
  958.         PUSH    SI
  959.         MOV    AX,2
  960.         CALL    OPEN_SPACE    ;make space for CR and LF
  961.         POP    DI        ;get back old cursor location
  962.         JC    FILE_FULL
  963.         MOV    AX,CRLF     ;LF*256+CR
  964.         STOSW            ;store the CR and LF
  965.         JMP    SHORT ADVANCE_NEW_LINE ;repaint the screen
  966.         ;(CALL/RETurn)
  967. INSERT_KEY    ENDP
  968.  
  969. ;---------------------------------------
  970. ; process the <Backspace> key, delete character left of cursor.
  971. ;---------------------------------------
  972. BACK_SPACE    PROC    NEAR
  973.         OR    SI,SI        ;is cursor at start of file?
  974.         JZ    FILE_FULL    ;if so, no delete right
  975.         CALL    LEFT        ;move left one space (flush UnDo buffer)
  976. ;**follows    JMP    DEL_CHAR    ;and delete the character (into buffer)
  977.         ;(CALL/RETurn)
  978. BACK_SPACE    ENDP
  979.  
  980. ;=======================================================================
  981. ; This routine deletes the character at the cursor by shifting the remaining 
  982. ; characters forward.  <Del> key
  983. ;-----------------------------------------------------------------------
  984. DEL_CHAR    PROC    NEAR
  985.         CMP    CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  986.         JA    NO_DEL        ;jump if read-only file
  987.         MOV    CX,LAST_CHAR
  988.         MOV    SI,CURSOR
  989.         MOV    DI,SI
  990.         CMP    SI,CX        ;are we at end of file?
  991.         JAE    NO_DEL        ;if yes, then don't delete
  992.         LODSB            ;loads char in AL, DS:SI
  993.         CALL    SAVE_CHAR    ;save it for UNDO function
  994.         MOV    AH,[SI]        ;look at the next character also
  995.         PUSH    AX        ;save character we're deleting
  996.         DEC    LAST_CHAR    ;shorten the file by one
  997.         SUB    CX,SI
  998.         REP    MOVSB        ;move file down one, DS:SI to ES:DI
  999.  
  1000.         POP    AX        ;get back character we deleted
  1001.         CMP    AX,CRLF        ;did we delete a CR?
  1002.         JE    COMBINE
  1003.         OR    DIRTY_BITS,4    ;current line is dirty
  1004.         ;-----------------------
  1005.         ; see if we made a CRLF by deleting a character.
  1006.         ; if we are in the middle of a CRLF, move the cursor back one.
  1007.         ;-----------------------
  1008.         JMP    SHORT C_IF_NEW_CRLF
  1009.         ;(CALL/RETurn) - saves a byte
  1010. ;---------------------------------------
  1011. COMBINE:                ;deleted an EOL marker, CR-LF
  1012.         CALL    DEL_CHAR    ;now delete the line feed (recursive)
  1013.                 MOV     DIRTY_BITS,3
  1014.                 MOV     DX,CURS_POSN
  1015.         MOV    SAVE_COLUMN,DL    ;save the cursor column
  1016. NO_DEL:
  1017.         RET
  1018. DEL_CHAR    ENDP
  1019.  
  1020. ;=======================================================================
  1021. ; see if we made a CR-LF pair with the cursor located on the LF character 
  1022. ; by joining the character (Ctrl-M) with a (Ctrl-J).  If so, back up the 
  1023. ; cursor and open a new line and return with carry set.  if not, return with 
  1024. ; carry clear.
  1025. ;-----------------------------------------------------------------------
  1026. C_IF_NEW_CRLF    PROC    NEAR
  1027.         MOV    SI,CS:CURSOR    ;present cursor location
  1028.         OR    SI,SI        ;is it at start of file
  1029.         JZ    DONE_CRLF
  1030.         CMP    WORD PTR [SI-1],CRLF ;did we make CR-LF?
  1031.         JNE    DONE_CRLF
  1032.         DEC    CS:CURSOR    ;move cursor back to point at CR code
  1033. C_IF_NEW_CRLF    ENDP
  1034.  
  1035. ;---------------------------------------
  1036. ; This routine opens a new line.
  1037. ;---------------------------------------
  1038. ADVANCE_NEW_LINE PROC    NEAR        ;split line on screen for CR-LF
  1039.         CALL    HOME        ;cursor to start of line
  1040.         CALL    DOWN        ;move down to the new line
  1041.         MOV    DIRTY_BITS,3    ;repaint the screen and cursor
  1042.         STC            ;C=1 if new line was done
  1043.         RET
  1044. DONE_CRLF:
  1045.         CLC            ;C=0 if not new line
  1046.         RET
  1047. ADVANCE_NEW_LINE ENDP
  1048.  
  1049. ;=======================================================================
  1050. ; This routine restores any characters which have recently been deleted.
  1051. ;-----------------------------------------------------------------------
  1052. UNDO        PROC    NEAR
  1053.     ;    ASSUME    DS:FILE_SEG
  1054.         XOR    AX,AX
  1055.         XCHG    AX,CS:UNDO_LENGTH ;get buffer length
  1056.         MOV    SI,OFFSET UNDO_BUFFER
  1057.         JMP    INSERT_STRING
  1058.         ;(CALL/RETurn)
  1059. UNDO        ENDP
  1060.  
  1061. ;=======================================================================
  1062. ; This routine inserts spaces into the file buffer.  On entry, AX
  1063. ; contains the number of spaces to be inserted.  On return, CF=1 if 
  1064. ; there was not enough space in the file buffer.
  1065. ;-----------------------------------------------------------------------
  1066. OPEN_SPACE    PROC    NEAR
  1067.     ;    ASSUME    DS:FILE_SEG
  1068.         MOV    CX,LAST_CHAR    ;last character in the file
  1069.         MOV    SI,CX
  1070.         MOV    DI,CX
  1071.         ADD    DI,AX        ;offset for new end of file
  1072.         JC    NO_ROOM        ;if no more room, return error
  1073.         MOV    LAST_CHAR,DI    ;save offset of end of file
  1074.         SUB    CX,CURSOR    ;number of characters to shift
  1075.         DEC    DI
  1076.         DEC    SI
  1077.         STD            ;string moves goes forward
  1078.         REP    MOVSB        ;shift the file upward
  1079.         CLD
  1080.         MOV    BYTE PTR DIRTY_FILE,0FFH ;file has been altered
  1081.         CLC
  1082. NO_ROOM:                ;carry is set if no room in file
  1083.         RET
  1084. OPEN_SPACE    ENDP
  1085.  
  1086. ;=======================================================================
  1087. ; This routine adds a character to the UNDO buffer.
  1088. ;-----------------------------------------------------------------------
  1089. SAVE_CHAR    PROC    NEAR
  1090.         MOV    BX,UNDO_LENGTH
  1091.         OR    BH,BH        ;is buffer filled?
  1092.         JNZ    NO_SAVE        ;buffer overflowed, no insert
  1093.         INC    UNDO_LENGTH
  1094.         MOV    BYTE PTR CS:UNDO_BUFFER[BX],AL
  1095.         MOV    BYTE PTR CS:DIRTY_FILE,0FFH ;file altered
  1096. NO_SAVE:
  1097.         RET
  1098. SAVE_CHAR    ENDP
  1099.  
  1100. ;=======================================================================
  1101. ; This routine deletes from the cursor position to the end of the line.
  1102. ;-----------------------------------------------------------------------
  1103. DEL_EOL        PROC    NEAR
  1104.         ;-----------------------
  1105.         ; from TEDPLUS,  modified by JEG, delete line if at column 1.
  1106. ;**Shft-F8    MOV    CX,CURSOR_POSN
  1107. ;**Shft-F8    JCXZ    DEL_L
  1108.         ;-----------------------
  1109.         CMP    CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  1110.         JA    NO_DEL_L    ;jump if read-only file
  1111.         MOV    LINE_FLAG,0
  1112.         PUSH    CURSOR        ;save starting cursor location
  1113.         CALL    ENDD        ;move to the end of the line
  1114.         POP    SI        ;get back starting cursor
  1115.         MOV    CX,CURSOR    ;offset of end of line
  1116.         MOV    CURSOR,SI    ;restore starting cursor
  1117.         JMP    SHORT DEL_END    ;delete characters to end of line
  1118.         ;(CALL/RETurn)
  1119. DEL_EOL        ENDP
  1120.  
  1121. ;-----------------------------------------------------------------------
  1122. ; This routine deletes a line, placing it in the line buffer. <F9>, <Shft-F8>
  1123. ;-----------------------------------------------------------------------
  1124. DEL_L        PROC    NEAR
  1125.         CMP    CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  1126.         JA    NO_DEL_L    ;jump if read-only file
  1127.          MOV    LINE_FLAG,1
  1128.         CALL    FIND_START    ;find start of this line
  1129.         MOV    CURSOR,SI    ;this will be the new cursor
  1130.         PUSH    SI        ;save the cursor position
  1131.         CALL    FIND_NEXT    ;find the next line
  1132.         MOV    CX,SI        ;CX will hold line length
  1133.         POP    SI        ;get back new cursor location
  1134. DEL_END:
  1135.         MOV    BYTE PTR DIRTY_FILE,0FFH ;file has been altered
  1136.  
  1137.         SUB    CX,SI        ;number of bytes on line
  1138.         OR    CH,CH        ;is line too long to fit?
  1139.         JZ    NOT_TOO_LONG
  1140.         MOV    CX,100H        ;save only 256 characters
  1141. NOT_TOO_LONG:
  1142.         MOV    LINE_LENGTH,CX    ;store length of deleted line
  1143.         JCXZ    NO_DEL_L
  1144.         MOV    DI,OFFSET LINE_BUFFER ;buffer for deleted line
  1145.  
  1146.         PUSH    CX
  1147.         PUSH    ES
  1148.         PUSH    CS
  1149.         POP    ES        ;line buffer is in CSEG
  1150.         REP    MOVSB        ;put deleted line in buffer
  1151.         POP    ES        ;get back file segment
  1152.         POP    AX
  1153.  
  1154.         MOV    CX,LAST_CHAR    ;get the file size
  1155.         SUB    LAST_CHAR,AX    ;subtract the deleted line
  1156.         MOV    SI,CURSOR    ;get new cursor location
  1157.         MOV    DI,SI
  1158.         ADD    SI,AX        ;SI points to end of file
  1159.         SUB    CX,SI        ;length of remaining file
  1160.         JCXZ    NO_DEL_L
  1161.         REP    MOVSB        ;shift remainder of file up
  1162. NO_DEL_L:
  1163.         MOV    DIRTY_BITS,3    ;redraw the screen and adjust cursor
  1164.         RET
  1165. DEL_L        ENDP
  1166.  
  1167. ;=======================================================================
  1168. ; This routine undeletes a line by copying it from the line buffer into 
  1169. ; the file.
  1170. ;-----------------------------------------------------------------------
  1171. UDEL_L        PROC    NEAR
  1172.         CMP    LINE_FLAG,0    ;is this an end of line only?
  1173.         JE    UDEL_EOL    ;if yes, don't home the cursor
  1174.         CALL    HOME        ;move cursor to home
  1175. UDEL_EOL:
  1176.         MOV    AX,LINE_LENGTH    ;length of deleted line
  1177.         MOV    SI,OFFSET LINE_BUFFER
  1178. ;**insert_str    JMP    INSERT_STRING    ;(follows immediately)
  1179.         ;(CALL/RETurn)
  1180. UDEL_L        ENDP
  1181.  
  1182. ;-----------------------------------------------------------------------
  1183. ; This routine inserts AX characters from CS:SI into the file.
  1184. ; (This routine follows "UDEL_L")
  1185. ;-----------------------------------------------------------------------
  1186. INSERT_STRING    PROC    NEAR
  1187.     ;    ASSUME    DS:FILE_SEG
  1188.         PUSH    SI        ;save string buffer
  1189.         MOV    SI,CS:CURSOR    ;get cursor offset
  1190.         PUSH    AX        ;save length of string
  1191.         PUSH    SI
  1192.         CALL    OPEN_SPACE    ;make space to insert string
  1193.         POP    DI        ;get back cursor position
  1194.         POP    CX        ;get back string length
  1195.         POP    SI        ;get back string buffer
  1196.         JC    NO_SPACE    ;if no space available, exit
  1197.  
  1198.         PUSH    DS
  1199.         PUSH    CS
  1200.         POP    DS
  1201.         ASSUME    DS:CSEG
  1202.         REP    MOVSB        ;copy characters DS:SI to ES:DI
  1203.         MOV    DIRTY_BITS,3    ;redraw the screen and adjust cursor
  1204.         POP    DS
  1205.         ASSUME    DS:NOTHING
  1206.         CALL    C_IF_NEW_CRLF
  1207. NO_SPACE:
  1208.         RET
  1209. INSERT_STRING    ENDP
  1210.  
  1211. ;=======================================================================
  1212. ; VIDEO services
  1213. ;=======================================================================
  1214. ; This routine displays a character by writing directly to 
  1215. ; the screen buffer.  To avoid screen noise (snow) on the color
  1216. ; card (CGA), the horizontal retrace has to be monitored.
  1217. ;-----------------------------------------------------------------------
  1218. WRITE_INVERSE    PROC    NEAR        
  1219.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1220.         MOV    BH,CS:INVERSE    ;attribute for inverse video
  1221.         JMP    SHORT WRITE_SCREEN
  1222. ;-----------------------------------------------------------------------
  1223. WRITE_FIND:
  1224.         MOV    BH,CS:SRCH_CLR    ;attribute for find string
  1225. ;        MOV    BH,CS:INVERSE    ;attribute for find string
  1226.         JMP    SHORT WRITE_SCREEN
  1227. ;-----------------------------------------------------------------------
  1228. WRITE_NORMAL:
  1229.         MOV    BH,CS:NORMAL    ;attribute for normal video
  1230. WRITE_SCREEN:
  1231.         MOV    BL,AL        ;save the character
  1232.         PUSH    ES
  1233.         LES    DX,CS:VIDEO_STATUS_REG ;video status register
  1234.         ;-------------------------------------------------------
  1235.         ; HWAIT is used to "desnow" the display for the CGA.
  1236.         ; If not CGA, the following instruction is modified to a 
  1237.         ; JMP   SHORT WRITE_IT
  1238.         ;-------------------------------------------------------
  1239. HWAIT:
  1240.         IN    AL,DX        ;get video status
  1241.         ROR    AL,1        ;look at horizontal retrace
  1242.         JNC    HWAIT        ;wait for retrace
  1243. WRITE_IT:
  1244.         MOV    AX,BX        ;get the character/attributes
  1245.         STOSW            ;write the character
  1246.         POP    ES
  1247.         RET
  1248. WRITE_INVERSE    ENDP
  1249.  
  1250. ;=======================================================================
  1251. ; This routine moves the cursor to the row/column in DX.
  1252. ;-----------------------------------------------------------------------
  1253. SET_CURSOR    PROC    NEAR
  1254.         XOR    BH,BH        ;we're using page zero
  1255.         MOV    AH,2        ;BIOS set cursor function
  1256.         INT    10H
  1257.         RET
  1258. SET_CURSOR    ENDP
  1259.  
  1260. ;=======================================================================
  1261. ; This routine computes the video buffer offset for the row/column in DX.
  1262. ;-----------------------------------------------------------------------
  1263. POSITION    PROC    NEAR
  1264.         MOV    AX,CS:COLUMNS    ;take columns per row
  1265.         MUL    DH        ;times row number
  1266.         XOR    DH,DH
  1267.         ADD    AX,DX        ;add the column number
  1268.         SHL    AX,1        ;times 2 for offset
  1269.         MOV    DI,AX        ;return result in DI
  1270.         RET
  1271. POSITION    ENDP
  1272.  
  1273. ;=======================================================================
  1274. ; This routine erases from the location in DX to the right edge of the screen.
  1275. ;-----------------------------------------------------------------------
  1276. ERASE_EOL    PROC    NEAR
  1277.         ASSUME    DS:NOTHING
  1278.         CALL    POSITION    ;find screen offset
  1279.         MOV    CX,CS:COLUMNS    ;get screen size
  1280.         SUB    CL,DL        ;subtract current position
  1281.         JCXZ    NO_CLEAR
  1282. ERASE_LOOP:
  1283.         MOV    AL," "        ;write blanks to erase
  1284.         CALL    WRITE_NORMAL    ;display it
  1285.         LOOP    ERASE_LOOP
  1286. NO_CLEAR:
  1287.         RET
  1288. ERASE_EOL    ENDP
  1289.  
  1290. ;=======================================================================
  1291. ; This routine displays the function key prompt and insert/overstrike mode 
  1292. ; state.  It sets DIRTY_BITS := 3 to force redraw of the entire screen 
  1293. ; and locate cursor.
  1294. ;-----------------------------------------------------------------------
  1295. REDO_PROMPT    PROC    NEAR
  1296.         ASSUME    DS:NOTHING, ES:NOTHING
  1297.         PUSH    DS
  1298.         PUSH    CS
  1299.         POP    DS
  1300.         ASSUME    DS:CSEG
  1301.         MOV    DH,ROWS        ;put prompt at last row
  1302.         INC    DH
  1303.         XOR    DL,DL        ;and column 0
  1304.         CALL    POSITION    ;convert to screen offset
  1305.         MOV    SI,OFFSET PROMPT_STRING
  1306. KEY_LOOP:
  1307.         MOV    AL,"F"        ;display an "F"
  1308.         CALL    WRITE_NORMAL
  1309.         LODSB
  1310.         OR    AL,AL        ;last key in prompt?
  1311.         JZ    PROMPT_DONE
  1312.         CALL    WRITE_NORMAL
  1313.  
  1314.         CMP    BYTE PTR CS:[SI],"0" ;is it F10?
  1315.         JNE    TEXT_LOOP
  1316.         LODSB
  1317.         CALL    WRITE_NORMAL
  1318. TEXT_LOOP:
  1319.         LODSB
  1320.         OR    AL,AL        ;last letter in word?
  1321.         JNZ    WRITE_CHAR
  1322.  
  1323.         MOV    AL," "        ;display a space
  1324.         CALL    WRITE_NORMAL
  1325.         JMP    KEY_LOOP
  1326. WRITE_CHAR:
  1327.         CALL    WRITE_INVERSE    ;display the letter
  1328.         JMP    TEXT_LOOP    ;do the next letter
  1329. PROMPT_DONE:
  1330.         MOV    DH,ROWS
  1331.         INC    DH        ;get the last row on the screen
  1332.         MOV    DL,PROMPT_LENGTH + 9
  1333.         CALL    ERASE_EOL    ;erase to the end of this row
  1334.         MOV    BL,INSERT_MODE
  1335.         XOR    BH,BH
  1336.         MOV    AL,CS:[BX + OFFSET INSERT_CODE]
  1337.     ;    MOV    AL,"O"        ;write an "O" (for "Overstrike")
  1338.     ;    CMP    INSERT_MODE,1    ;in insert mode?
  1339.     ;    JB    OVERSTRIKE
  1340.     ;    MOV    AL,"I"        ;write an "I" (for "Insert")
  1341.     ;    JE    OVERSTRIKE
  1342.     ;    MOV    AL,"R"        ;write an "R" (for "read-only")
  1343. OVERSTRIKE:
  1344.         DEC    DI        ;backup one character position
  1345.         DEC    DI
  1346.         CALL    WRITE_NORMAL
  1347.         MOV    DIRTY_BITS,3    ;now redraw the entire screen
  1348.         POP    DS
  1349.         ASSUME    DS:NOTHING
  1350.         RET
  1351. REDO_PROMPT    ENDP
  1352.  
  1353. ;=======================================================================
  1354. ; This routine displays the file buffer on the screen.
  1355. ; DISPLAY_BOTTOM has been deleted to reduce the program code size.
  1356. ;-----------------------------------------------------------------------
  1357. DISPLAY_SCREEN    PROC    NEAR
  1358.         ASSUME    DS:FILE_SEG, ES:FILE_SEG
  1359.  
  1360.                 TEST    DIRTY_BITS,2    ;see if we should adjust the cursor
  1361.         JZ    DISP_CURS_OK
  1362.         MOV    SI,CURSOR    ;get the new cursor offset
  1363.         MOV    DX,CURS_POSN    ;also get the current row
  1364.         CALL    LOCATE        ;adjust the cursor screen position
  1365. DISP_CURS_OK:
  1366.  
  1367.                 MOV     DX,CURS_POSN
  1368.         MOV    SAVE_ROW,DH
  1369.         CALL    SET_CURSOR    ;position the cursor
  1370.  
  1371.                 TEST    DIRTY_BITS,1    ;see if we should update the screen
  1372.                 JNZ     DO_UPDATE_SCREEN
  1373.  
  1374.                 TEST    DIRTY_BITS,4    ;is the current line dirty?
  1375.                 JZ      DISP_DONE       ;if not, take jump
  1376.                 CALL    DISPLAY_CURRENT ;redraw the current line
  1377.                 JMP     SHORT DISP_DONE
  1378.  
  1379. DO_UPDATE_SCREEN:
  1380.                 MOV     SI,TOP_OF_SCREEN ;point to first char on screen
  1381.         XOR    DH,DH        ;start at first row
  1382. ;        JMP    SHORT NEXT_ROW
  1383. ;        ;-----------------------
  1384. ;DISPLAY_BOTTOM:                ;this redraws the bottom only
  1385. ;        CALL    FIND_START    ;find first character on this row
  1386. ;        MOV    DX,CURS_POSN    ;get current cursor row
  1387. NEXT_ROW:
  1388.         PUSH    DX
  1389.         CALL    DISPLAY_LINE    ;display a line
  1390.         POP    DX
  1391.         ;-----------------------
  1392.         ; the keyboard is tested here to see if a key is waiting
  1393.         ;-----------------------
  1394.         MOV    AH,1
  1395.         INT    16H
  1396.         MOV    AL,1        ;for dirty_bits, update not completed
  1397.         JNZ    DISP_NOT_DONE    ;jump if there is a key is waiting
  1398.  
  1399.         INC    DH        ;move to the next row
  1400.         CMP    DH,ROWS        ;at end of screen yet?
  1401.         JBE    NEXT_ROW    ;do all the rows
  1402. DISP_DONE:
  1403.                 MOV     AL,0
  1404. DISP_NOT_DONE:
  1405.                 MOV     DIRTY_BITS,AL   ;screen is completely redone
  1406.         RET
  1407. DISPLAY_SCREEN    ENDP
  1408.  
  1409. ;=======================================================================
  1410. ; This routine displays a single line to the screen.  DH holds the 
  1411. ; row number, SI has the offset into the file buffer.  Tabs are expanded.  
  1412. ; Adjustment is made for side shift.
  1413. ;-----------------------------------------------------------------------
  1414. DISPLAY_CURRENT    PROC    NEAR
  1415.     ;    ASSUME    DS:FILE_SEG
  1416.         CALL    FIND_START
  1417.         MOV    DX,CS:CURS_POSN
  1418. DISPLAY_CURRENT ENDP
  1419.         ;-----------------------
  1420. DISPLAY_LINE    PROC    NEAR        ;external entry point
  1421.         XOR    DL,DL        ;start at column zero
  1422.         MOV    CS:MARGIN_COUNT,DL
  1423.         MOV    CX,DX        ;use CL to count the columns
  1424.         CALL    POSITION    ;compute offset into video
  1425. NEXT_CHAR:
  1426.         CMP    SI,LAST_CHAR    ;at end of file?
  1427.         JAE    LINE_DONE
  1428.         LODSB            ;get next character, DS:SI
  1429.         CMP    AL,TAB        ;is this a Tab character?
  1430.         JE    EXPAND_TAB    ;if yes, expand to spaces
  1431.  
  1432.         CMP    SI,LAST_CHAR    ;at end of file now?
  1433.         JAE    DO_PUT        ;jump, can't be CR-LF pair
  1434.  
  1435.         CMP    WORD PTR [SI-1],CRLF ;EOL marker
  1436.         JE    FOUND_CR    ;quit when a CR-LF is found
  1437. DO_PUT:
  1438.         CALL    PUT_CHAR    ;put character onto screen
  1439. TAB_DONE:
  1440.         CMP    CL,CS:COLUMNSB    ;at right edge of screen?
  1441.         JB    NEXT_CHAR
  1442.         ;-----------------------
  1443.         ; from TEDPLUS
  1444.         INC    SI
  1445.         CMP    SI,LAST_CHAR    ;at end of file?
  1446.         DEC    SI
  1447.         JAE    NOT_BEYOND
  1448.         CMP    WORD PTR [SI],CRLF ;at end of line?
  1449.         ;----------------------
  1450.         JE    NOT_BEYOND
  1451. DO_DIAMOND:
  1452.         DEC    DI        ;backup one character
  1453.         DEC    DI
  1454.         MOV    AL,4        ;show a diamond
  1455.         CALL    WRITE_INVERSE    ;in inverse video
  1456. NOT_BEYOND:
  1457.         JMP    FIND_NEXT    ;find start of next line
  1458.         ;(CALL/RETurn)
  1459. ;---------------------------------------
  1460. EXPAND_TAB:
  1461.         MOV    AL," "        ;convert tab to spaces
  1462.         CALL    PUT_CHAR
  1463.         MOV    AL,MARGIN_COUNT
  1464.         ADD    AL,CL        ;CL is column count
  1465.         TEST    AL,00000111B    ;at even multiples of eight?
  1466.         JNZ    EXPAND_TAB    ;if not, keep adding spaces
  1467.         JMP    TAB_DONE
  1468. ;---------------------------------------
  1469. FOUND_CR:
  1470.         INC    SI        ;past the CR-LF
  1471. LINE_DONE:
  1472.         MOV    DX,CX
  1473.         JMP    ERASE_EOL    ;erase the end of the line
  1474.         ;(CALL/RETurn)
  1475.         ;-----------------------
  1476. DISPLAY_LINE    ENDP
  1477.  
  1478. ;=======================================================================
  1479. ; This routine displays a single character to the screen.  If the character 
  1480. ; is marked, it is shown in inverse video.  Characters outside the current 
  1481. ; margin are not displayed.  Characters left of the margin are skipped.
  1482. ;-----------------------------------------------------------------------
  1483. PUT_CHAR    PROC    NEAR
  1484.     ;    ASSUME    DS:FILE_SEG
  1485.         MOV    BL,MARGIN_COUNT    ;get distance to left margin
  1486.         CMP    BL,LEFT_MARGIN    ;are we inside left margin?
  1487.         JAE    IN_WINDOW    ;yes, show the character
  1488.         INC    BL
  1489.         MOV    MARGIN_COUNT,BL
  1490.         RET
  1491.         ;-----------------------
  1492.         ; from TEDPLUS
  1493. IN_WINDOW:
  1494.         CMP    SRCH_FLG,0
  1495.         JE    CKM
  1496.         CMP    SI,SRCH_BASE
  1497.         JBE    CKM
  1498.         CMP    SI,SRCH_END
  1499.         JA    CKM
  1500.         CALL    WRITE_FIND
  1501. ;**inverse    CALL    WRITE_INVERSE    ;found string highlighted, inverse video
  1502.         JMP    SHORT NEXT_COL
  1503. CKM:
  1504.         ;-----------------------
  1505.         CMP    SI,MARK_START    ;is this character marked?
  1506.         JBE    NOT_MARKED
  1507.         CMP    SI,MARK_END
  1508.         JA    NOT_MARKED
  1509.         CALL    WRITE_INVERSE    ;marked characters shown inverse
  1510.         JMP    SHORT NEXT_COL
  1511.         ;-----------------------
  1512. NOT_MARKED:
  1513.         CALL    WRITE_NORMAL
  1514. NEXT_COL:
  1515.         INC    CL        ;increment the column count
  1516.         RET
  1517. PUT_CHAR    ENDP
  1518.  
  1519. ;=======================================================================
  1520. ; This routine adjusts the cursor position ahead to the saved cursor column.  
  1521. ; On entry DH has the cursor row.
  1522. ;-----------------------------------------------------------------------
  1523. SHIFT_RIGHT    PROC    NEAR
  1524.     ;    ASSUME    DS:FILE_SEG
  1525.         MOV    CL,SAVE_COLUMN    ;keep the saved cursor offset
  1526.         XOR    CH,CH
  1527.         MOV    BP,CX        ;keep the saved cursor position
  1528.         ADD    CL,LEFT_MARGIN    ;shift into visible window
  1529.         ADC    CH,0
  1530.         XOR    DL,DL
  1531.         MOV    CURS_POSN,DX    ;get cursor row/column
  1532.         JCXZ    NO_CHANGE
  1533. RIGHT_AGAIN:
  1534.         PUSH    CX
  1535.         ;-----------------------
  1536.         ; (JEG)
  1537.         INC    SI
  1538.         CMP    SI,LAST_CHAR    ;at end of file?
  1539.         DEC    SI
  1540.         JAE    DO_MOVE
  1541.         CMP    WORD PTR [SI],CRLF ;at end of line?
  1542.         ;-----------------------
  1543.         JE    DONT_MOVE    ;if at end, stop moving
  1544. DO_MOVE:
  1545.         CALL    RIGHT        ;move right one character
  1546. DONT_MOVE:
  1547.         POP    CX
  1548.  
  1549.         MOV    AL,SAVE_COLUMN
  1550.         XOR    AH,AH
  1551.         CMP    AX,CX        ;is cursor still in margin?
  1552.         JL    IN_MARGIN    ;if yes, keep moving
  1553.  
  1554.         MOV    DX,CURS_POSN    ;get cursor column again
  1555.         XOR    DH,DH
  1556.         CMP    DX,BP        ;at saved cursor position?
  1557.         JE    RIGHT_DONE    ;if yes, we're done
  1558.         JA    RIGHT_TOO_FAR    ;did we go too far?
  1559. IN_MARGIN:
  1560.         LOOP    RIGHT_AGAIN
  1561. RIGHT_DONE:
  1562.         MOV    CX,BP
  1563.         MOV    SAVE_COLUMN,CL    ;get back saved cursor position
  1564. NO_CHANGE:
  1565.         RET
  1566.         ;-----------------------
  1567. RIGHT_TOO_FAR:
  1568.         CALL    LEFT        ;move back left one place
  1569.         MOV    CX,BP
  1570.         MOV    SAVE_COLUMN,CL    ;get back saved cursor position
  1571.         RET
  1572. SHIFT_RIGHT    ENDP
  1573.  
  1574. ;=======================================================================
  1575. ; This routine finds the beginning of the previous line.
  1576. ;-----------------------------------------------------------------------
  1577. FIND_PREVIOUS    PROC    NEAR
  1578.     ;    ASSUME    DS:FILE_SEG
  1579.         PUSH    CURSOR        ;save the cursor location
  1580.         CALL    FIND_CR        ;find the start of this line
  1581.         MOV    CURSOR,SI    ;save the new cursor
  1582.         CALL    FIND_START    ;find the start of this line
  1583.         POP    CURSOR        ;get back starting cursor
  1584.         RET
  1585. FIND_PREVIOUS    ENDP
  1586.  
  1587. ;=======================================================================
  1588. ; This routine searches for the previous carriage return.  
  1589. ; Search starts at DS:SI.
  1590. ;-----------------------------------------------------------------------
  1591. FIND_CR        PROC    NEAR
  1592.     ;    ASSUME    DS:FILE_SEG
  1593.         PUSH    CX
  1594.         MOV    AL,LF        ;look for a line feed character
  1595.         MOV    DI,SI
  1596.         MOV    CX,SI
  1597.         JCXZ    AT_BEGINNING
  1598.         DEC    DI
  1599.         STD            ;search backwards
  1600. LF_PREV:
  1601.         REPNE    SCASB        ;scan for the character
  1602.         ;-----------------------
  1603.         ; from TEDPLUS
  1604.         JCXZ    LF_END
  1605.         CMP    BYTE PTR [DI],CR
  1606.         JNE    LF_PREV
  1607.         DEC    DI
  1608. LF_END:
  1609.         ;-----------------------
  1610.         CLD            ;restore the direction flag
  1611.         INC    DI
  1612.         MOV    SI,DI
  1613. AT_BEGINNING:
  1614.         POP    CX
  1615.         RET
  1616. FIND_CR        ENDP
  1617.  
  1618. ;=======================================================================
  1619. ; This routine skips past the CR and LF at SI.  SI returns new offset.
  1620. ;-----------------------------------------------------------------------
  1621. SKIP_CR_LF    PROC    NEAR
  1622.     ;    ASSUME    CS:FILE_SEG
  1623.         CMP    SI,LAST_CHAR    ;at last char in file?
  1624.         JAE    NO_SKIP        ;if yes, don't skip anything
  1625.         CMP    BYTE PTR [SI],CR ;is first character a CR?
  1626.         JNE    NO_SKIP
  1627.         INC    SI        ;look at next character
  1628.         CMP    SI,LAST_CHAR    ;is it at the end of file?
  1629.         JAE    NO_SKIP        ;if yes, don't skip anymore
  1630.         CMP    BYTE PTR [SI],LF ;is next character a line feed?
  1631.         JNE    NO_SKIP        ;skip any line feeds also
  1632.         INC    SI
  1633. NO_SKIP:
  1634.         RET
  1635. SKIP_CR_LF    ENDP
  1636.  
  1637. ;=======================================================================
  1638. ; This routine computes the location of the start of current line.  
  1639. ; Returns SI pointing to the first character of the current line.  
  1640. ;-----------------------------------------------------------------------
  1641. FIND_START    PROC    NEAR
  1642.     ;    ASSUME    DS:FILE_SEG
  1643.         MOV    SI,CURSOR    ;get the current cursor
  1644.         OR    SI,SI        ;at start of file?
  1645.         JZ    AT_START    ;if yse, we're done
  1646.         CALL    FIND_CR        ;find the CR
  1647.         CALL    SKIP_CR_LF
  1648. AT_START:
  1649.         RET
  1650. FIND_START    ENDP
  1651.  
  1652. ;=======================================================================
  1653. ; This routine finds the offset of the start of the next line.  The search 
  1654. ; is started at location of ES:SI.  On return, CF=1 if no CR was found.
  1655. ;-----------------------------------------------------------------------
  1656. FIND_NEXT    PROC    NEAR
  1657.     ;    ASSUME    DS:FILE_SEG
  1658.         PUSH    CX
  1659.         CALL    FIND_EOL    ;find the end of this line
  1660.         JC    AT_NEXT        ;if at end of file, return
  1661.         CALL    SKIP_CR_LF    ;skip past CR and LF
  1662.         CLC            ;indicate end of line found
  1663. AT_NEXT:
  1664.         POP    CX
  1665.         RET
  1666. FIND_NEXT    ENDP
  1667.  
  1668. ;=======================================================================
  1669. ; This routine searches for the next carriage return in the file.  
  1670. ; The search starts at the offset in register SI.  
  1671. ;-----------------------------------------------------------------------
  1672. FIND_EOL    PROC    NEAR
  1673.     ;    ASSUME    DS:FILE_SEG
  1674.         MOV    AL,CR        ;look for a carriage return
  1675. CR_SCAN:
  1676.         MOV    CX,LAST_CHAR    ;last letter in the file
  1677.         SUB    CX,SI        ;count for the search
  1678.         MOV    DI,SI
  1679.         JCXZ    AT_END        ;if nothing to search, return
  1680.         REPNE    SCASB        ;scan for the character
  1681.         MOV    SI,DI        ;return the location of the CR
  1682.         JCXZ    AT_END        ;if not found, return
  1683.         ;-----------------------
  1684.         ; from TEDPLUS
  1685.         CMP    BYTE PTR [SI],LF
  1686.         JNE    CR_SCAN
  1687.         ;-----------------------
  1688.         DEC    SI        ;back up one, to CR character
  1689.         CLC            ;indicate the CR was found
  1690.         RET
  1691. AT_END:
  1692.         STC            ;indicate CR was not found
  1693.         RET
  1694. FIND_EOL    ENDP
  1695.  
  1696. ;=======================================================================
  1697. ; This routine positions the screen with the cursor at the row 
  1698. ; selected in register DH.  On entry, SI holds the cursor offset.
  1699. ;-----------------------------------------------------------------------
  1700. LOCATE        PROC    NEAR
  1701.     ;    ASSUME    DS:FILE_SEG
  1702.         MOV    CL,DH
  1703.         XOR    CH,CH
  1704.         MOV    CURSOR,SI
  1705.         XOR    DX,DX        ;start at top of screen
  1706.         OR    SI,SI        ;at start of buffer?
  1707.         JZ    LOCATE_FIRST
  1708.  
  1709.         CALL    FIND_START    ;get start of this row
  1710.         XOR    DX,DX        ;start at top of screen
  1711.         OR    SI,SI        ;is cursor at top of file?
  1712.         JZ    LOCATE_FIRST
  1713.         JCXZ    LOCATE_FIRST    ;if location to top row were done
  1714. FIND_TOP:
  1715.         PUSH    SI
  1716.         PUSH    CX
  1717.         CALL    FIND_CR        ;find previous row
  1718.         POP    CX
  1719.         POP    AX
  1720.         CMP    WORD PTR [SI],CRLF
  1721.         JNE    LOCATE_FIRST
  1722.         CMP    SI,AX        ;did it change?
  1723.         JE    LOCATE_DONE    ;if not, quit moving
  1724.         INC    DH        ;cursor moves to next row
  1725.         LOOP    FIND_TOP
  1726.  
  1727. LOCATE_DONE:
  1728.         PUSH    CURSOR
  1729.         MOV    CURSOR,SI
  1730.         CALL    FIND_START    ;find start at top of screen
  1731.         POP    CURSOR
  1732. LOCATE_FIRST:
  1733.         MOV    TOP_OF_SCREEN,SI
  1734.         MOV    CURS_POSN,DX
  1735.         CALL    CURSOR_COL
  1736.         MOV    SAVE_COLUMN,DL
  1737.         RET
  1738. LOCATE        ENDP
  1739.  
  1740. ;=======================================================================
  1741. ; This routine computes the correct column for the cursor.  No inputs.  
  1742. ; On exit, CURS_POSN is set and DX has row/column.
  1743. ;-----------------------------------------------------------------------
  1744. CURSOR_COL    PROC    NEAR
  1745.     ;    ASSUME    DS:FILE_SEG
  1746.         MOV    SI,CURSOR    ;get cursor offset
  1747.         CALL    FIND_START    ;find start of this line
  1748.         MOV    CX,CURSOR    ;cursor location in file
  1749.         SUB    CX,SI
  1750.         MOV    DX,CURS_POSN    ;get current row
  1751.         XOR    DL,DL        ;start at column zero
  1752.         MOV    MARGIN_COUNT,DL    ;count past the left margin
  1753.         JCXZ    COL_DONE
  1754. CURSOR_LOOP:
  1755.         LODSB            ;get the next character
  1756.         INC    SI
  1757.         CMP    SI,LAST_CHAR
  1758.         DEC    SI
  1759.         JAE    NOT_EOL        ;is <CR> without <LF>, at end of file
  1760.  
  1761.         CMP    WORD PTR [SI-1],CRLF ;(JEG)
  1762.         JE    COL_DONE    ;if at end, we're done
  1763. NOT_EOL:
  1764.         CMP    AL,TAB        ;is it a tab?
  1765.         JNE    NOT_A_TAB
  1766.  
  1767.         MOV    BL,MARGIN_COUNT
  1768.         OR    BL,00000111B
  1769.         MOV    MARGIN_COUNT,BL
  1770.         CMP    BL,LEFT_MARGIN    ;inside visible window yet?
  1771.         JB    NOT_A_TAB    ;if not, don't advance cursor
  1772.         OR    DL,00000111B    ;move to multiple of eight
  1773. NOT_A_TAB:
  1774.         MOV    BL,MARGIN_COUNT
  1775.         INC    BL
  1776.         MOV    MARGIN_COUNT,BL
  1777.         CMP    BL,LEFT_MARGIN
  1778.         JBE    OUT_OF_WINDOW
  1779.         INC    DL        ;we're at next column now
  1780. OUT_OF_WINDOW:
  1781.         LOOP    CURSOR_LOOP
  1782. COL_DONE:
  1783.         CMP    DL,COLUMNSB    ;past end of display?
  1784.         JB    COLUMN_OK    ;if not, we're OK
  1785.         MOV    DL,COLUMNSB
  1786.         DEC    DL        ;leave cursor at last column
  1787. COLUMN_OK:
  1788.         MOV    CURS_POSN,DX    ;store at last column
  1789.         RET
  1790. CURSOR_COL    ENDP
  1791.  
  1792. ;=======================================================================
  1793. ; MARK, CUT, PASTE, PRINT services
  1794. ;=======================================================================
  1795. ; This routine toggles the mark state and resets the paste buffer pointers.
  1796. ;-----------------------------------------------------------------------
  1797. MARK        PROC    NEAR
  1798.         XOR    AX,AX
  1799.         NOT    CS:MARK_MODE    ;toggle the mode flag
  1800.         CMP    CS:MARK_MODE,AL    ;turning mode ON?
  1801.         JNE    MARK_ON
  1802.         OR    CS:DIRTY_BITS,1    ;need to redraw the screen
  1803.         MOV    CS:MARK_START,0FFFFH
  1804.         JMP    SHORT MARK_RET
  1805.         ;-----------------------
  1806. MARK_ON:
  1807.         MOV    AX,CS:CURSOR    ;get the cursor offset
  1808.         MOV    CS:MARK_START,AX    ;start of marked range
  1809. MARK_RET:
  1810.         MOV    CS:MARK_END,AX    ;end of marked range
  1811.         MOV    CS:MARK_HOME,AX    ;center of marked range
  1812.         RET
  1813. MARK        ENDP
  1814.  
  1815. ;=======================================================================
  1816. ; This routine removes the marked text and places it in the paste buffer.
  1817. ;-----------------------------------------------------------------------
  1818. CUT        PROC    NEAR
  1819.         CMP    CS:INSERT_MODE,1 ;in insert mode? (0=ovr,1=ins,2 or 3=RO)
  1820.         JA    NO_MARK        ;jump if read-only file
  1821.         CMP    CS:MARK_MODE,0    ;is the mark mode on?
  1822.         JE    NO_MARK        ;if not, then do nothing
  1823.         MOV    CX,CS:MARK_END    ;get end of mark region
  1824.         MOV    SI,CS:MARK_START ;get start of mark region
  1825.         SUB    CX,SI        ;number of bytes selected
  1826.         MOV    PASTE_SIZE,CX
  1827.         XOR    DI,DI        ;point to paste buffer
  1828.  
  1829.         PUSH    CX
  1830.         PUSH    ES
  1831.         MOV    ES,CS:PASTE_SEG    ;set the paste buffer segment to ES
  1832.         REP    MOVSB        ;deleted text to buffer, DS:SI to ES:DI
  1833.         POP    ES
  1834.         POP    AX
  1835.  
  1836.         MOV    CX,CS:LAST_CHAR
  1837.         SUB    CS:LAST_CHAR,AX    ;shorten the file this much
  1838.         MOV    DI,CS:MARK_START
  1839.         MOV    SI,CS:MARK_END
  1840.         SUB    CX,SI
  1841.         JCXZ    NO_DELETE
  1842.         REP    MOVSB        ;shorten the file, DS:SI to ES:DI
  1843. NO_DELETE:
  1844.         MOV    DX,CS:CURS_POSN
  1845.         MOV    SI,CS:MARK_START
  1846.         CALL    LOCATE        ;adjust the screen position
  1847.         CALL    MARK        ;this turns off select
  1848.  
  1849.         ;-----------------------
  1850.         ; see if we made a CR-LF pair by cutting the character(s) from
  1851.         ; between a Ctrl-M and a Ctrl-J.  If so, open a new line.
  1852.         ;-----------------------
  1853.         CALL    C_IF_NEW_CRLF
  1854.  
  1855. NO_MARK:
  1856.         RET
  1857. CUT        ENDP
  1858.  
  1859. ;=======================================================================
  1860. ; This routine copies the paste buffer into the file at the cursor location.
  1861. ;-----------------------------------------------------------------------
  1862. PASTE        PROC    NEAR
  1863.         MOV    AX,PASTE_SIZE    ;number of characters in buffer
  1864.         OR    AX,AX        ;any there?
  1865.         JZ    NO_PASTE    ;if not, nothing to paste
  1866.  
  1867.         MOV    SI,CURSOR    ;get cursor location
  1868.         PUSH    AX
  1869.         PUSH    SI
  1870.         CALL    OPEN_SPACE    ;make room for new characters
  1871.         POP    DI
  1872.         POP    CX
  1873.         JC    NO_PASTE    ;if no room, just exit
  1874.         XOR    SI,SI        ;point to start of paste buffer
  1875.         PUSH    DS
  1876.         MOV    DS,PASTE_SEG    ;segment of paste buffer
  1877.         REP    MOVSB        ;copy in the new characters
  1878.         POP    DS
  1879.         OR    DIRTY_BITS,1    ;redraw the screen
  1880.         CALL    C_IF_NEW_CRLF
  1881.  
  1882. NO_PASTE:
  1883.         RET
  1884. PASTE        ENDP
  1885.  
  1886. ;=======================================================================
  1887. ; This routine prints an ASCII Form-Feed character.
  1888. ;-----------------------------------------------------------------------
  1889. PRINT_FF    PROC    NEAR
  1890.         CALL    MARK        ;toggle MARK "on"
  1891.         PUSH    DS
  1892.         PUSH    CS
  1893.         POP    DS        
  1894.         MOV    CX,1        ;one character to print
  1895.         MOV    SI,OFFSET FF    ;offset of last byte in paste buffer
  1896.         CALL    DO_FF_CHAR
  1897.         POP    DS
  1898.         RET
  1899.  
  1900. FF        DB    12        ;the ASCII Form-Feed character
  1901. PRINT_FF    ENDP
  1902. ;-----------------------------------------------------------------------
  1903. ; This routine prints the marked text.  If printer fails, it is cancelled.
  1904. ;-----------------------------------------------------------------------
  1905. PRINT        PROC    NEAR
  1906.         CMP    MARK_MODE,0    ;is mark mode on?
  1907.         JE    PRINT_RET    ;if not, nothing to print
  1908.         MOV    CX,MARK_END    ;end of marked region
  1909.         MOV    SI,MARK_START    ;start of marked region
  1910.         SUB    CX,SI        ;number of bytes selected
  1911.         JCXZ    PRINT_DONE    ;if nothing to print, return
  1912. DO_FF_CHAR:
  1913.         XOR    DX,DX        ;select printer 0
  1914.         MOV    AH,2
  1915.         INT    17H        ;get printer status
  1916.         TEST    AH,10000000B    ;is busy bit set?
  1917.         JZ    PRINT_DONE
  1918.         TEST    AH,00100000B    ;is printer out of paper?
  1919.         JNZ    PRINT_DONE
  1920. PRINT_LOOP:
  1921.         LODSB
  1922.         XOR    AH,AH
  1923.         INT    17H        ;print the character
  1924.         ROR    AH,1        ;check the time out bit
  1925.         JC    PRINT_DONE    ;if set, quit printing
  1926.         LOOP    PRINT_LOOP
  1927.         MOV    AL,CR
  1928. ;------ [typographical error in article]
  1929. ;**nop!        XOR    AH,0        ;[would be No-Operation]
  1930.         XOR    AH,AH
  1931. ;------
  1932.         INT    17H        ;finish with a CR
  1933. PRINT_DONE:
  1934.         CALL    MARK        ;turn off the mark status
  1935. PRINT_RET:
  1936.         RET
  1937. PRINT        ENDP
  1938.  
  1939. ;=======================================================================
  1940. ; CHARACTER STRING SEARCH and SEARCH AGAIN services; HELP screen
  1941. ;=======================================================================
  1942. ; from TEDPLUS
  1943. ; This routine is used to search or search again for a character string.
  1944. ;-----------------------------------------------------------------------
  1945. FIND_STR    PROC    NEAR
  1946.         PUSH    DS
  1947.         MOV    BX,CS
  1948.         MOV    DS,BX
  1949.         ASSUME    DS:CSEG
  1950. ;---------------------------------------
  1951. ;** now ShftF6    CMP    AH,66H        ;Is it shift F9
  1952.         CMP    AH,89        ;Is it shift-F6 (JEG)
  1953. ;---------------------------------------
  1954.         JE    RPT_FIND
  1955.         MOV    DH,ROWS
  1956.         INC    DH        ;Last row on the screen
  1957.         XOR    DL,DL        ;First column
  1958.         MOV    SI,OFFSET SRCH_PROMPT
  1959.         CALL    TTY_STRING    ;Display search prompt
  1960.         MOV    DX, OFFSET SRCH_MAX
  1961.         MOV    AH,0AH
  1962.         INT    21H        ;Read input string
  1963. RPT_FIND:
  1964.         XOR    DX,DX
  1965.         MOV    DL,BYTE PTR SRCH_SIZ
  1966.         ADD    DX,OFFSET SRCH_STR
  1967.         MOV    DI,DX
  1968.         DEC    DI
  1969.         MOV    SRCH_END,DI
  1970.         XOR    DX,DX
  1971.         MOV    SI,CURSOR
  1972.         INC    SI
  1973.         MOV    SRCH_BASE,SI
  1974. S_REDO:
  1975.         MOV    DI,OFFSET SRCH_STR
  1976.         MOV    BX,SRCH_BASE
  1977. S_CYCLE:    MOV    AL,[DI]
  1978.         MOV    AH,AL        ;CONVERT AL TO OPPOSITE AND PUT IN AH
  1979.         CMP    AL,'A'
  1980.         JB    S_CMP
  1981.         CMP    AL,'Z'
  1982.         JA    TSTLO
  1983.         XOR    AH,20H        ;toggle letter case
  1984.         JMP    SHORT S_CMP
  1985. TSTLO:        CMP    AL,'a'
  1986.         JB    S_CMP
  1987.         CMP    AL,'z'
  1988.         JA    S_CMP
  1989.         XOR    AH,20H        ;toggle letter case
  1990. S_CMP:        CMP    BX,LAST_CHAR
  1991.         JA    END_MCH
  1992.         CMP    AL,ES:[BX]
  1993.         JE    S_MCH
  1994.         CMP    AH,ES:[BX]
  1995.         JE    S_MCH
  1996.         CMP    DI,OFFSET SRCH_STR
  1997.         JNE    S_REDO
  1998.         INC    BX
  1999.         CMP    WORD PTR ES:[BX-1],CRLF ;test for EOL marker
  2000.         JNE    S_BX1
  2001.         INC    DL
  2002. S_BX1:        JMP    SHORT S_CMP
  2003.         
  2004. S_MCH:        INC    BX
  2005.         CMP    DI,OFFSET SRCH_STR
  2006.         JNE    NO_BSE
  2007.         MOV    SRCH_BASE,BX
  2008. NO_BSE:        ADD    DH,DL
  2009.         XOR    DL,DL
  2010.         CMP    DI,SRCH_END
  2011.         JE    YEA_MCH
  2012.         INC    DI
  2013.         JMP    SHORT S_CYCLE
  2014. YEA_MCH:    
  2015.         MOV    SRCH_FLG,1
  2016.         MOV    SI,SRCH_BASE
  2017.         DEC    SI
  2018.         MOV    SRCH_BASE,SI
  2019.         MOV    CURSOR,SI
  2020.         XOR    BX,BX
  2021.         MOV    BL,BYTE PTR SRCH_SIZ
  2022.         ADD    BX,SI
  2023.         MOV    SRCH_END,BX
  2024.         XOR    DL,DL
  2025.         ADD    DX,CURS_POSN
  2026.         CMP    DH,ROWS
  2027.         JBE    NEW_S
  2028.         XOR    DX,DX
  2029. NEW_S:
  2030.         POP    DS        ;ASSUME is no longer valid
  2031.         CALL    LOCATE
  2032.                 JMP     SHORT END_MCH2
  2033. END_MCH:                
  2034.         POP    DS
  2035. END_MCH2:
  2036.                 CALL    REDO_PROMPT     ;redraw the prompt and the screen
  2037.         RET
  2038. FIND_STR    ENDP
  2039.  
  2040. ;=======================================================================
  2041. ; This routine displays a user help screen
  2042. ;-----------------------------------------------------------------------
  2043. HELP        PROC    NEAR
  2044.         PUSH    DS
  2045.         PUSH    CS
  2046.         POP    DS
  2047.         ASSUME    DS:CSEG        ;for func-9, display message
  2048.         CALL    CLR_SCREEN
  2049.  
  2050.         MOV    DX,OFFSET HELP_SCREEN    ;message is at DS:DX in CSEG
  2051.         MOV    AH,9        ;display message
  2052.         INT    21H
  2053. HELP_WAIT_KEY:
  2054.         MOV    AH,1        ;wait for any key pressed
  2055.         INT    16H
  2056.         JZ    HELP_WAIT_KEY
  2057.         MOV    AH,0
  2058.         INT    16H
  2059.  
  2060.         POP    DS
  2061.         ASSUME    DS:NOTHING
  2062.         JMP    REDO_PROMPT    ;redraw the prompt and the screen
  2063.         ;(CALL/RETurn)
  2064. HELP        ENDP
  2065.  
  2066. ;=======================================================================
  2067. ; This routine prompts for a filename then writes the file.  The original 
  2068. ; file is renamed to filename.BAK.  If an invalid filename is entered, the 
  2069. ; speaker is beeped.  If the file has not been altered, the edit file is 
  2070. ; abandoned and control is immediately returned to DOS.  
  2071. ;-----------------------------------------------------------------------
  2072. EXIT        PROC    NEAR
  2073.         PUSH    DS        ;save in case ESC key
  2074.         PUSH    ES
  2075.         MOV    AX,CS
  2076.         MOV    DS,AX
  2077.         MOV    ES,AX
  2078.         ASSUME    DS:CSEG, ES:CSEG
  2079.         TEST    BYTE PTR DIRTY_FILE,0FFH ;is the file altered?
  2080.         JNZ    NEXT_LETTER    ;(jump was out of range)
  2081.         JMP    FINISHED    ;file has not been altered, no save.
  2082.         ;-----------------------
  2083. IS_BACKSPACE:
  2084.         CMP    DI,NAME_POINTER    ;at first letter?
  2085.         JLE    NEXT_LETTER    ;if yes, don't erase it
  2086.         MOV    BYTE PTR [DI-1],0
  2087.         DEC    NAME_END
  2088.  
  2089. NEXT_LETTER:
  2090.         MOV    DH,ROWS
  2091.         INC    DH        ;last row on the screen
  2092.         XOR    DL,DL        ;first column
  2093.         MOV    SI,OFFSET SAVE_MESS
  2094.         PUSH    DX
  2095.         CALL    TTY_STRING    ;display a prompt
  2096.         POP    DX
  2097.         ADD    DL,9        ;move right 9 spaces
  2098.         MOV    SI,NAME_POINTER
  2099.         CALL    TTY_STRING    ;display the filename
  2100.  
  2101.         XOR    AH,AH        ;read the next key
  2102.         INT    16H
  2103.         MOV    DI,NAME_END    ;this points to the last letter
  2104.         OR    AL,AL        ;is it a real character?
  2105. ;        JZ    NEXT_LETTER    ;ignore special keys
  2106.         JZ    IS_ESCAPE    ;special keys return to edit mode
  2107.         CMP    AL,1BH        ;is it ESCape?
  2108.         JE    IS_ESCAPE    ;continue with exit procedure
  2109.         CMP    AL,CR        ;is it CR?
  2110.         JE    GOT_NAME
  2111.         CMP    AL,08H        ;is it a backspace?
  2112.         JE    IS_BACKSPACE
  2113.         CMP    DI,81H + 65    ;too many letters?
  2114.         JG    NEXT_LETTER    ;if yes, ignore them
  2115.         XOR    AH,AH        ;for new terminal 0 to string
  2116.         STOSW            ;store the new letter and 0
  2117.         INC    NAME_END    ;name is one character longer
  2118.         JMP    NEXT_LETTER    ;read another keystroke
  2119.         ;-----------------------
  2120. IS_ESCAPE:
  2121.         POP    ES        ;get back file segment
  2122.         POP    DS
  2123.         JMP    REDO_PROMPT    ;redraw the prompt and the screen
  2124.         ;(CALL/RETurn)        ;return to edit mode
  2125.         ;-----------------------
  2126. GOT_NAME:
  2127.         MOV    DX,NAME_POINTER    ;point to the filename
  2128.         MOV    AX,4300H    ;get the file attribute
  2129.         INT    21H        ;DOS call
  2130.         JNC    NAME_OK        ;if no error, filename is OK
  2131.         CMP    AX,3        ;was it "path not found" error?
  2132.         JE    BAD_NAME    ;if yes, filename was bad
  2133. NAME_OK:
  2134.         MOV    SI,OFFSET DOT_$$$    ;point to the ".$$$"
  2135.         MOV    DI,OFFSET NAME_DOT_$$$
  2136.         CALL    CHG_EXTENSION        ;add the new extension
  2137.  
  2138.         MOV    DX,OFFSET NAME_DOT_$$$    ;point to temp filename
  2139.         MOV    CX,0020H        ;attribute for new file
  2140.         MOV    AH,3CH            ;function to create file
  2141.         INT    21H            ;DOS call
  2142.         JNC    NAME_WAS_OK        ;continue if name was OK
  2143. BAD_NAME:
  2144.         MOV    AX,0E07H    ;write a bell character
  2145.         INT    10H        ;BIOS TTY service
  2146.         JMP    NEXT_LETTER    ;get another letter
  2147.         ;-----------------------
  2148. WRITE_ERROR:
  2149.         MOV    AH,3EH        ;close the file
  2150.         INT    21H        ;DOS call
  2151.         JMP    BAD_NAME    ;filename must be bad
  2152.         ;-----------------------
  2153. NAME_WAS_OK:
  2154.         XOR    DX,DX        ;this is the file buffer
  2155.         MOV    CX,LAST_CHAR    ;number of chars in file
  2156.         MOV    BX,AX        ;this is the handle
  2157.         MOV    AH,40H        ;write to the file
  2158.         POP    DS        ;recover the buffer segment
  2159.         INT    21H        ;write the buffer contents
  2160.         POP    DS
  2161.         JC    WRITE_ERROR    ;exit on a write error
  2162.         CMP    AX,CX        ;was entire file written?
  2163.         JNE    WRITE_ERROR    ;if not, exit
  2164.  
  2165.         PUSH    CS
  2166.         POP    DS            ;get the code segment
  2167.         MOV    AH,3EH            ;close the temp file
  2168.         INT    21H            ;DOS call
  2169.         MOV    SI,OFFSET DOT_BAK    ;point to the ".BAK"
  2170.         MOV    DI,OFFSET NAME_DOT_BAK
  2171.         CALL    CHG_EXTENSION        ;make the backup filename
  2172.  
  2173.         MOV    DX,OFFSET NAME_DOT_BAK    ;point to the backup name
  2174.         MOV    AH,41H            ;delete existing backup file
  2175.         INT    21H            ;DOS call
  2176.         MOV    DI,OFFSET NAME_DOT_BAK
  2177.         MOV    DX,NAME_POINTER
  2178.         MOV    AH,56H
  2179.         INT    21H            ;DOS call
  2180.  
  2181.         MOV    DI,NAME_POINTER    ;point to new filename
  2182.         MOV    DX,OFFSET NAME_DOT_$$$ ;point to temporary file
  2183.         MOV    AH,56H        ;rename temp to new file
  2184.         INT    21H        ;DOS call, rename
  2185.         POP    AX        ;restore the stack
  2186.         POP    AX
  2187.         JMP    SHORT FINISHED
  2188.         ;(To return to DOS)
  2189. EXIT        ENDP
  2190.  
  2191. ;-----------------------------------------------------------------------
  2192. ; This routine prompts for a verify keystroke then exits without saving 
  2193. ; the file.  If the file has not been altered, the edit file is abandoned 
  2194. ; and control is immediately returned to DOS.  
  2195. ;-----------------------------------------------------------------------
  2196. ABORT        PROC    NEAR
  2197.         PUSH    CS
  2198.         POP    DS
  2199.         ASSUME    DS:CSEG
  2200.         TEST    BYTE PTR DIRTY_FILE,0FFH ;is the file altered?
  2201.         JZ    FINISHED    ;file has not been altered.
  2202.  
  2203.         MOV    DH,ROWS        ;last row on display
  2204.         INC    DH        ;bottom row on screen
  2205.         XOR    DL,DL        ;first column
  2206.         MOV    SI,OFFSET VERIFY_MESS
  2207.         CALL    TTY_STRING    ;display verify message
  2208.  
  2209.         XOR    AH,AH        ;read the next key
  2210.         INT    16H        ;BIOS read key routine
  2211.         CMP    AL,CR        ;is it CR?
  2212.         JE    FINISHED
  2213.         OR    AL,20H        ;convert to lower case
  2214.         CMP    AL,"y"        ;was answer Yes?
  2215.         JE    FINISHED    ;if yes, then we're finished
  2216.         CALL    REDO_PROMPT    ;redraw the prompt and the screen
  2217.         PUSH    ES
  2218.         POP    DS        ;set DS back to file segment
  2219.         RET            ;return to edit mode
  2220.         ;-----------------------
  2221. FINISHED:
  2222.         MOV    DX,OFFSET COPYRIGHT
  2223.         ;-----------------------
  2224. EXIT_TO_DOS:                ;External entry point (DX, message)
  2225.         PUSH    CS
  2226.         POP    DS        ;point to code segment
  2227.         ASSUME    DS:CSEG
  2228.         CALL    CLR_SCREEN    ;clear the screen (passes DX through)
  2229.         MOV    AH,9        ;display error/exit message DS:DX
  2230.         INT    21H        ;DOS call
  2231.         MOV    AX,EXIT_CODE    ;Exit to DOS with exit code
  2232.         INT    21H        ;DOS call
  2233.  
  2234. ABORT        ENDP
  2235.  
  2236. ;=======================================================================
  2237. ; This routine copies the input filename to CS:DI and changes the extension.
  2238. ;-----------------------------------------------------------------------
  2239. CHG_EXTENSION    PROC    NEAR
  2240.         ASSUME    DS:CSEG, ES:CSEG
  2241.         PUSH    SI
  2242.         MOV    SI,NAME_POINTER
  2243. CHG_LOOP:
  2244.         LODSB
  2245.         CMP    AL,"."        ;look for the extension
  2246.         JE    FOUND_DOT
  2247.         OR    AL,AL
  2248.         JZ    FOUND_DOT
  2249.         STOSB            ;copy a character
  2250.         JMP    CHG_LOOP
  2251.         ;-----------------------
  2252. FOUND_DOT:
  2253.         MOV    CX,5        ;five characters in extension
  2254.         POP    SI
  2255.         REP    MOVSB        ;move new extension in
  2256.         RET
  2257. CHG_EXTENSION    ENDP
  2258.  
  2259. ;=======================================================================
  2260. ; This routine displays the string at CS:SI at the location in DX.  The 
  2261. ; remainder of the row is erased.  Cursor is put at the end of the line.
  2262. ;-----------------------------------------------------------------------
  2263. TTY_STRING    PROC    NEAR
  2264.         ASSUME    DS:CSEG
  2265.         PUSH    DX
  2266.         CALL    POSITION    ;compute offset into video
  2267.         POP    DX
  2268. TTY_LOOP:
  2269.         LODSB            ;load DS:SI to AL
  2270.         OR    AL,AL        ;at end of string yet?
  2271.         JZ    TTY_DONE
  2272.         INC    DL
  2273.         PUSH    DX
  2274.         CALL    WRITE_INVERSE    ;write in inverse video
  2275.         POP    DX
  2276.         JMP    TTY_LOOP
  2277.         ;-----------------------
  2278. TTY_DONE:
  2279.         CALL    SET_CURSOR    ;move cursor to end of string
  2280.         JMP    ERASE_EOL    ;erase the rest of the line
  2281.         ;(CALL/RETurn)
  2282. TTY_STRING    ENDP
  2283.  
  2284. ;=======================================================================
  2285. ; This routine clears the screen, leaves registers unaltered.
  2286. ;-----------------------------------------------------------------------
  2287. CLR_SCREEN    PROC    NEAR
  2288.         ASSUME    DS:NOTHING
  2289.         PUSH    AX        ;save registers (for INT-24)
  2290.         PUSH    BX
  2291.         PUSH    CX
  2292.         PUSH    DX        ;save DX for message address
  2293.          MOV    DL,79        ;DL = right column
  2294.         MOV    DH,CS:ROWS    ;DH = lower row
  2295.         INC    DH        ;to clear the last line on the screen
  2296.         MOV    CX,0        ;CH = upper row, CL = left column
  2297.         MOV    BH,CS:NORMAL    ;BH is blank line attribute, 07 = normal video
  2298.         MOV    AX,0600H    ;scroll the cursor up (blank line)
  2299.         INT    10H
  2300.         XOR    DX,DX        ;set cursor to top left of screen
  2301.         CALL    SET_CURSOR
  2302.         POP    DX
  2303.         POP    CX
  2304.         POP    BX
  2305.         POP    AX
  2306.         RET
  2307. CLR_SCREEN    ENDP
  2308.  
  2309. ;=======================================================================
  2310. ; This is the control break handler for MS-DOS.  It ignores the break.
  2311. ; TED then responds by entering a <Ctrl-C> in the file.
  2312. ;-----------------------------------------------------------------------
  2313. NEWINT23    PROC    FAR
  2314.         ASSUME    DS:NOTHING, ES:NOTHING
  2315.         MOV    CS:DIRTY_BITS,1    ;to redraw the screen
  2316.         CLC            ;tell DOS to ignore break
  2317.         IRET
  2318. NEWINT23    ENDP
  2319.  
  2320. ;=======================================================================
  2321. ; This is the severe error handler.  It homes the cursor before 
  2322. ; processing the error.
  2323. ;-----------------------------------------------------------------------
  2324. NEWINT24    PROC    FAR
  2325.         ASSUME    DS:NOTHING, ES:NOTHING
  2326.         PUSHF
  2327.         CALL    CLR_SCREEN    ;clear the screen and home the cursor
  2328.         POPF
  2329.         JMP    CS:OLDINT24
  2330.         ;(chain to old INT 24 handler)
  2331. NEWINT24    ENDP
  2332.  
  2333. ;=======================================================================
  2334. ; This is the location of the character string search buffer.  It occupies 
  2335. ; the last three bytes in the program file.  The following 64-bytes are used 
  2336. ; for the buffer area.  The third byte is also used as the program code 
  2337. ; check-sum compensation byte.
  2338. ;-----------------------------------------------------------------------
  2339.         EVEN
  2340. SRCH_MAX    DB    66        ;42H, maximum size of buffer
  2341. SRCH_SIZ    DB    0        ;number of char's actually in buffer
  2342. SRCH_STR    DB    0        ;start of buffer block
  2343.  
  2344.         ;This is the correction byte for the check-sum test
  2345. CHEK_SUM_BYT    DB      0103
  2346.  
  2347. ;=======================================================================
  2348.  
  2349. NAME_DOT_$$$    EQU    $ +64        ;128 bytes
  2350. NAME_DOT_BAK    EQU    $+80H +64    ;128 bytes
  2351. UNDO_BUFFER    EQU    $+100H +64    ;256 bytes, Del key buffer
  2352. LINE_BUFFER    EQU    $+200H +64    ;256 bytes, Delete line, EOL
  2353.  
  2354. END_BUFFER    EQU    $+300H +64 +15    ;end of buffers, file segment follows
  2355.                     ; +15 is for paragraph rounding
  2356.  
  2357.  
  2358. CSEG    ENDS
  2359.  
  2360. ;-----------------------------------------------------------------------
  2361.  
  2362. FILE_SEG    SEGMENT
  2363. FILE_SEG    ENDS
  2364.  
  2365. END        START